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 217621 : 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 9529 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
166 : {
167 9529 : const SharedDatasetCtxt *psStruct =
168 : static_cast<const SharedDatasetCtxt *>(elt);
169 : return static_cast<unsigned long>(
170 9529 : CPLHashSetHashStr(psStruct->pszDescription) ^
171 9529 : CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
172 9529 : psStruct->nOpenFlags ^ psStruct->nPID);
173 : }
174 :
175 7991 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
176 : {
177 7991 : const SharedDatasetCtxt *psStruct1 =
178 : static_cast<const SharedDatasetCtxt *>(elt1);
179 7991 : const SharedDatasetCtxt *psStruct2 =
180 : static_cast<const SharedDatasetCtxt *>(elt2);
181 15953 : return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
182 7962 : strcmp(psStruct1->pszConcatenatedOpenOptions,
183 7962 : psStruct2->pszConcatenatedOpenOptions) == 0 &&
184 23915 : psStruct1->nPID == psStruct2->nPID &&
185 15953 : psStruct1->nOpenFlags == psStruct2->nOpenFlags;
186 : }
187 :
188 417 : static void GDALSharedDatasetFreeFunc(void *elt)
189 : {
190 417 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
191 417 : CPLFree(psStruct->pszDescription);
192 417 : CPLFree(psStruct->pszConcatenatedOpenOptions);
193 417 : CPLFree(psStruct);
194 417 : }
195 :
196 : static std::string
197 8121 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
198 : {
199 8121 : std::string osStr;
200 8134 : for (const char *pszOption : cpl::Iterate(papszOpenOptions))
201 13 : osStr += pszOption;
202 8121 : 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 488457 : CPLMutex **GDALGetphDLMutex()
211 : {
212 488457 : return &hDLMutex;
213 : }
214 :
215 : // The current thread will act in the behalf of the thread of PID
216 : // responsiblePID.
217 476823 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
218 : {
219 : GIntBig *pResponsiblePID =
220 476823 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
221 476823 : if (pResponsiblePID == nullptr)
222 : {
223 223 : pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
224 223 : CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
225 : }
226 476823 : *pResponsiblePID = responsiblePID;
227 476823 : }
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 615448 : GIntBig GDALGetResponsiblePIDForCurrentThread()
232 : {
233 : GIntBig *pResponsiblePID =
234 615448 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
235 615448 : if (pResponsiblePID == nullptr)
236 45650 : return CPLGetPID();
237 569798 : 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 181639 : GDALDataset::GDALDataset()
264 181639 : : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
265 : {
266 181639 : }
267 :
268 217621 : GDALDataset::GDALDataset(int bForceCachedIOIn)
269 217621 : : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
270 217621 : m_poPrivate(new (std::nothrow) GDALDataset::Private)
271 : {
272 217621 : }
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 217594 : 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 217594 : if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
301 : {
302 77605 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
303 207 : CPLDebug("GDAL",
304 : "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
305 207 : GetDescription(), this, static_cast<int>(CPLGetPID()),
306 207 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
307 : else
308 77398 : CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
309 : }
310 :
311 217594 : GDALDataset::Close();
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Remove dataset from the "open" dataset list. */
315 : /* -------------------------------------------------------------------- */
316 217594 : if (!bIsInternal)
317 : {
318 158624 : CPLMutexHolderD(&hDLMutex);
319 79312 : if (poAllDatasetMap)
320 : {
321 : std::map<GDALDataset *, GIntBig>::iterator oIter =
322 79312 : poAllDatasetMap->find(this);
323 79312 : CPLAssert(oIter != poAllDatasetMap->end());
324 :
325 79312 : UnregisterFromSharedDataset();
326 :
327 79312 : poAllDatasetMap->erase(oIter);
328 :
329 79312 : if (poAllDatasetMap->empty())
330 : {
331 31674 : delete poAllDatasetMap;
332 31674 : poAllDatasetMap = nullptr;
333 31674 : if (phSharedDatasetSet)
334 : {
335 256 : CPLHashSetDestroy(phSharedDatasetSet);
336 : }
337 31674 : phSharedDatasetSet = nullptr;
338 31674 : CPLFree(ppDatasets);
339 31674 : ppDatasets = nullptr;
340 : }
341 : }
342 : }
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* Destroy the raster bands if they exist. */
346 : /* -------------------------------------------------------------------- */
347 1777600 : for (int i = 0; i < nBands && papoBands != nullptr; ++i)
348 : {
349 1560000 : if (papoBands[i] != nullptr)
350 1560000 : delete papoBands[i];
351 1560000 : papoBands[i] = nullptr;
352 : }
353 :
354 217594 : CPLFree(papoBands);
355 :
356 217594 : if (m_poStyleTable)
357 : {
358 23 : delete m_poStyleTable;
359 23 : m_poStyleTable = nullptr;
360 : }
361 :
362 217594 : if (m_poPrivate != nullptr)
363 : {
364 217594 : if (m_poPrivate->hMutex != nullptr)
365 22754 : 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 435188 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
370 : #endif
371 217594 : CPLFree(m_poPrivate->m_pszWKTCached);
372 217594 : if (m_poPrivate->m_poSRSCached)
373 : {
374 0 : m_poPrivate->m_poSRSCached->Release();
375 : }
376 217594 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
377 217594 : if (m_poPrivate->m_poSRSGCPCached)
378 : {
379 0 : m_poPrivate->m_poSRSGCPCached->Release();
380 : }
381 : }
382 :
383 217594 : delete m_poPrivate;
384 :
385 217594 : CSLDestroy(papszOpenOptions);
386 217594 : }
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 354451 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
474 : {
475 : (void)pfnProgress;
476 : (void)pProgressData;
477 :
478 354451 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
479 : {
480 : // Call UnregisterFromSharedDataset() before altering nOpenFlags
481 217594 : UnregisterFromSharedDataset();
482 :
483 217594 : nOpenFlags = OPEN_FLAGS_CLOSED;
484 : }
485 :
486 354451 : if (IsMarkedSuppressOnClose())
487 : {
488 3646 : 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 1777 : (!EQUAL(poDriver->GetDescription(), "MEM") &&
495 1697 : !EQUAL(poDriver->GetDescription(), "Memory")))
496 : {
497 1789 : if (VSIUnlink(GetDescription()) == 0)
498 689 : UnMarkSuppressOnClose();
499 : }
500 : }
501 :
502 354451 : 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 18 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
569 : GDALProgressFunc pfnProgress,
570 : void *pProgressData)
571 : {
572 18 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
573 18 : 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 249 : bool GDALDataset::GetCloseReportsProgress() const
593 : {
594 249 : 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 296906 : void GDALDataset::UnregisterFromSharedDataset()
645 : {
646 296906 : if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
647 296489 : return;
648 :
649 834 : CPLMutexHolderD(&hDLMutex);
650 :
651 : std::map<GDALDataset *, GIntBig>::iterator oIter =
652 417 : poAllDatasetMap->find(this);
653 417 : CPLAssert(oIter != poAllDatasetMap->end());
654 417 : const GIntBig nPIDCreatorForShared = oIter->second;
655 417 : bShared = false;
656 : SharedDatasetCtxt sStruct;
657 417 : sStruct.nPID = nPIDCreatorForShared;
658 417 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
659 417 : sStruct.pszDescription = const_cast<char *>(GetDescription());
660 : std::string osConcatenatedOpenOptions =
661 834 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
662 417 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
663 417 : sStruct.poDS = nullptr;
664 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
665 417 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
666 417 : if (psStruct && psStruct->poDS == this)
667 : {
668 416 : 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 79938 : void GDALDataset::AddToDatasetOpenList()
684 : {
685 : /* -------------------------------------------------------------------- */
686 : /* Add this dataset to the open dataset list. */
687 : /* -------------------------------------------------------------------- */
688 79938 : bIsInternal = false;
689 :
690 79938 : CPLMutexHolderD(&hDLMutex);
691 :
692 79938 : if (poAllDatasetMap == nullptr)
693 31685 : poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
694 79938 : (*poAllDatasetMap)[this] = -1;
695 79938 : }
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 142535 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
724 :
725 : {
726 142535 : CPLErr eErr = CE_None;
727 : // This sometimes happens if a dataset is destroyed before completely
728 : // built.
729 :
730 142535 : if (papoBands)
731 : {
732 1981840 : for (int i = 0; i < nBands; ++i)
733 : {
734 1855590 : if (papoBands[i])
735 : {
736 1855590 : if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
737 7 : eErr = CE_Failure;
738 : }
739 : }
740 : }
741 :
742 142535 : const int nLayers = GetLayerCount();
743 : // cppcheck-suppress knownConditionTrueFalse
744 142535 : if (nLayers > 0)
745 : {
746 18548 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
747 27724 : for (int i = 0; i < nLayers; ++i)
748 : {
749 18450 : OGRLayer *poLayer = GetLayer(i);
750 :
751 18450 : if (poLayer)
752 : {
753 18450 : if (poLayer->SyncToDisk() != OGRERR_NONE)
754 1 : eErr = CE_Failure;
755 : }
756 : }
757 : }
758 :
759 142535 : 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 5330 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
774 :
775 : {
776 5330 : VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
777 :
778 5330 : 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 3431 : GIntBig GDALDataset::GetEstimatedRAMUsage()
860 : {
861 3431 : 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 1705580 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1007 :
1008 : {
1009 : /* -------------------------------------------------------------------- */
1010 : /* Do we need to grow the bands list? */
1011 : /* -------------------------------------------------------------------- */
1012 1705580 : if (nBands < nNewBand || papoBands == nullptr)
1013 : {
1014 969781 : GDALRasterBand **papoNewBands = nullptr;
1015 :
1016 969781 : if (papoBands == nullptr)
1017 117070 : papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1018 117070 : sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1019 : else
1020 : papoNewBands = static_cast<GDALRasterBand **>(
1021 852711 : VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1022 852711 : std::max(nNewBand, nBands)));
1023 969781 : if (papoNewBands == nullptr)
1024 : {
1025 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1026 : "Cannot allocate band array");
1027 0 : return;
1028 : }
1029 :
1030 969781 : papoBands = papoNewBands;
1031 :
1032 1885510 : for (int i = nBands; i < nNewBand; ++i)
1033 915730 : papoBands[i] = nullptr;
1034 :
1035 969781 : nBands = std::max(nBands, nNewBand);
1036 :
1037 969781 : if (m_poPrivate)
1038 : {
1039 969781 : for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1040 2675360 : i < nBands; ++i)
1041 : {
1042 1705580 : 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 1705580 : 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 1705580 : 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 1705580 : poBand->nBand = nNewBand;
1065 1705580 : poBand->poDS = this;
1066 1705580 : poBand->nRasterXSize = nRasterXSize;
1067 1705580 : poBand->nRasterYSize = nRasterYSize;
1068 1705580 : 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 1114220 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1086 : {
1087 1114220 : SetBand(nNewBand, poBand.release());
1088 1114220 : }
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 743538 : int GDALDataset::GetRasterXSize() const
1107 : {
1108 743538 : 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 40721 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1122 :
1123 : {
1124 40721 : VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1125 :
1126 40721 : 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 622842 : int GDALDataset::GetRasterYSize() const
1144 : {
1145 622842 : 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 39931 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1159 :
1160 : {
1161 39931 : VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1162 :
1163 39931 : 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 12500100 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1186 :
1187 : {
1188 12500100 : if (papoBands)
1189 : {
1190 12500100 : 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 12500100 : 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 111 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1223 :
1224 : {
1225 111 : if (papoBands)
1226 : {
1227 111 : 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 111 : 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 414973 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1250 :
1251 : {
1252 414973 : VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1253 :
1254 414973 : return GDALRasterBand::ToHandle(
1255 414973 : 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 6271680 : int GDALDataset::GetRasterCount() const
1271 : {
1272 6271680 : 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 388188 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1286 :
1287 : {
1288 388188 : VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1289 :
1290 388188 : 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 5274 : const char *GDALDataset::GetProjectionRef() const
1319 : {
1320 5274 : const auto poSRS = GetSpatialRef();
1321 5274 : if (!poSRS || !m_poPrivate)
1322 : {
1323 2380 : return "";
1324 : }
1325 2894 : char *pszWKT = nullptr;
1326 2894 : poSRS->exportToWkt(&pszWKT);
1327 2894 : 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 5788 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1336 2894 : if (m_poPrivate->m_pszWKTCached &&
1337 752 : strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1338 : {
1339 751 : CPLFree(pszWKT);
1340 751 : return m_poPrivate->m_pszWKTCached;
1341 : }
1342 2143 : CPLFree(m_poPrivate->m_pszWKTCached);
1343 2143 : m_poPrivate->m_pszWKTCached = pszWKT;
1344 2143 : 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 18029 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1375 : {
1376 18029 : if (tlsEnableLayersInGetSpatialRefCounter == 0)
1377 17984 : return GetSpatialRefVectorOnly();
1378 45 : 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 17984 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1399 : {
1400 17984 : bool bInit = false;
1401 17984 : const OGRSpatialReference *poGlobalSRS = nullptr;
1402 34174 : for (const OGRLayer *poLayer : GetLayers())
1403 : {
1404 16172 : for (const auto *poGeomFieldDefn :
1405 48539 : poLayer->GetLayerDefn()->GetGeomFields())
1406 : {
1407 16177 : const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1408 16177 : if (!bInit)
1409 : {
1410 213 : bInit = true;
1411 213 : poGlobalSRS = poSRS;
1412 : }
1413 31924 : else if (((poSRS != nullptr) != (poGlobalSRS != nullptr)) ||
1414 15960 : (poSRS && !poSRS->IsSame(poGlobalSRS)))
1415 : {
1416 5 : CPLDebug("GDAL",
1417 : "Not all geometry fields or layers have the same CRS");
1418 5 : return nullptr;
1419 : }
1420 : }
1421 : }
1422 17979 : 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 1096 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1439 : {
1440 1096 : ++tlsEnableLayersInGetSpatialRefCounter;
1441 1096 : const auto poRet = GetSpatialRef();
1442 1096 : --tlsEnableLayersInGetSpatialRefCounter;
1443 1096 : 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 8349 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1461 :
1462 : {
1463 8349 : VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1464 :
1465 8349 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1466 8349 : 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 1455 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1480 :
1481 : {
1482 1455 : VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1483 :
1484 1455 : 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 2611 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
1510 : {
1511 2611 : if (pszProjection && pszProjection[0] != '\0')
1512 : {
1513 4836 : OGRSpatialReference oSRS;
1514 2418 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1515 2418 : if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1516 : {
1517 2 : return CE_Failure;
1518 : }
1519 2416 : return SetSpatialRef(&oSRS);
1520 : }
1521 : else
1522 : {
1523 193 : 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 1529 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1569 :
1570 : {
1571 1529 : VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1572 :
1573 3058 : return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1574 1529 : 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 1943 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1588 : const char *pszProjection)
1589 :
1590 : {
1591 1943 : VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1592 :
1593 1943 : 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 16374 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform >) const
1630 :
1631 : {
1632 16374 : gt = GDALGeoTransform();
1633 :
1634 16374 : 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 9873 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1688 :
1689 : {
1690 9873 : VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1691 :
1692 19746 : return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1693 9873 : *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 4582 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1765 : const double *padfTransform)
1766 :
1767 : {
1768 4582 : VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1769 4582 : VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1770 :
1771 9164 : return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1772 4582 : *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 171 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1792 :
1793 : {
1794 171 : 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 64 : void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1808 : const char *pszRequest)
1809 :
1810 : {
1811 64 : VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1812 :
1813 64 : 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 37900 : GDALDriver *GDALDataset::GetDriver() const
1830 : {
1831 37900 : 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 2782 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1845 :
1846 : {
1847 2782 : VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1848 :
1849 : return static_cast<GDALDriverH>(
1850 2782 : 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 266236 : int GDALDataset::Reference()
1868 : {
1869 266236 : 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 1531 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1883 :
1884 : {
1885 1531 : VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1886 :
1887 1531 : 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 331106 : int GDALDataset::Dereference()
1906 : {
1907 331106 : 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 63698 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1921 :
1922 : {
1923 63698 : VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1924 :
1925 63698 : 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 253033 : int GDALDataset::ReleaseRef()
1938 :
1939 : {
1940 253033 : if (Dereference() <= 0)
1941 : {
1942 7506 : nRefCount = 1;
1943 7506 : delete this;
1944 7506 : return TRUE;
1945 : }
1946 245527 : 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 1716 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1960 :
1961 : {
1962 1716 : VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1963 :
1964 1716 : 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 326781 : int GDALDataset::GetShared() const
1978 : {
1979 326781 : return bShared;
1980 : }
1981 :
1982 : /************************************************************************/
1983 : /* MarkAsShared() */
1984 : /************************************************************************/
1985 :
1986 : /**
1987 : * \brief Mark this dataset as available for sharing.
1988 : */
1989 :
1990 450 : void GDALDataset::MarkAsShared()
1991 :
1992 : {
1993 450 : CPLAssert(!bShared);
1994 :
1995 450 : bShared = true;
1996 450 : if (bIsInternal)
1997 32 : return;
1998 :
1999 418 : GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
2000 :
2001 : // Insert the dataset in the set of shared opened datasets.
2002 836 : CPLMutexHolderD(&hDLMutex);
2003 418 : if (phSharedDatasetSet == nullptr)
2004 260 : phSharedDatasetSet =
2005 260 : CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2006 : GDALSharedDatasetFreeFunc);
2007 :
2008 : SharedDatasetCtxt *psStruct =
2009 418 : static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2010 418 : psStruct->poDS = this;
2011 418 : psStruct->nPID = nPID;
2012 418 : psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2013 418 : psStruct->pszDescription = CPLStrdup(GetDescription());
2014 : std::string osConcatenatedOpenOptions =
2015 836 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2016 418 : psStruct->pszConcatenatedOpenOptions =
2017 418 : CPLStrdup(osConcatenatedOpenOptions.c_str());
2018 418 : 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 417 : CPLHashSetInsert(phSharedDatasetSet, psStruct);
2028 :
2029 417 : (*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 1283 : void GDALDataset::MarkSuppressOnClose()
2042 : {
2043 1283 : bSuppressOnClose = true;
2044 1283 : }
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 690 : void GDALDataset::UnMarkSuppressOnClose()
2070 : {
2071 690 : bSuppressOnClose = false;
2072 690 : }
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 258 : void GDALDataset::CleanupPostFileClosing()
2084 : {
2085 258 : 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 258 : }
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 16883 : int GDALDataset::GetGCPCount()
2107 : {
2108 16883 : return 0;
2109 : }
2110 :
2111 : /************************************************************************/
2112 : /* GDALGetGCPCount() */
2113 : /************************************************************************/
2114 :
2115 : /**
2116 : * \brief Get number of GCPs.
2117 : *
2118 : * @see GDALDataset::GetGCPCount()
2119 : */
2120 :
2121 2326 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2122 :
2123 : {
2124 2326 : VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2125 :
2126 2326 : 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 1051 : const char *GDALDataset::GetGCPProjection() const
2148 : {
2149 1051 : const auto poSRS = GetGCPSpatialRef();
2150 1051 : if (!poSRS || !m_poPrivate)
2151 : {
2152 713 : 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 43 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2197 : {
2198 43 : 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 1030 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2233 :
2234 : {
2235 1030 : VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2236 :
2237 1030 : 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 581 : const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2269 :
2270 : {
2271 581 : VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2272 :
2273 581 : 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 51 : CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2309 : const char *pszGCPProjection)
2310 :
2311 : {
2312 51 : 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 18 : return SetGCPs(nGCPCount, pasGCPList,
2325 18 : 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 28 : CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2383 : const GDAL_GCP *pasGCPList,
2384 : const char *pszGCPProjection)
2385 :
2386 : {
2387 28 : VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2388 :
2389 28 : return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2390 28 : 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 767 : 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 767 : int *panAllBandList = nullptr;
2474 :
2475 1534 : CPLStringList aosOptions(papszOptions);
2476 767 : 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 56 : GDALValidateOptions(GDALDriver::ToHandle(poDriver), pszOptionList,
2520 28 : aosOptions.List(), "overview creation option",
2521 : osDriver);
2522 : }
2523 : }
2524 :
2525 767 : if (nListBands == 0)
2526 : {
2527 755 : nListBands = GetRasterCount();
2528 : panAllBandList =
2529 755 : static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2530 67514 : for (int i = 0; i < nListBands; ++i)
2531 66759 : panAllBandList[i] = i + 1;
2532 :
2533 755 : panBandList = panAllBandList;
2534 : }
2535 :
2536 767 : if (pfnProgress == nullptr)
2537 732 : pfnProgress = GDALDummyProgress;
2538 :
2539 1868 : for (int i = 0; i < nOverviews; ++i)
2540 : {
2541 1102 : if (panOverviewList[i] <= 0)
2542 : {
2543 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2544 : "panOverviewList[%d] = %d is invalid. It must be a "
2545 : "positive value",
2546 1 : i, panOverviewList[i]);
2547 1 : CPLFree(panAllBandList);
2548 1 : return CE_Failure;
2549 : }
2550 : }
2551 :
2552 766 : const CPLErr eErr = IBuildOverviews(
2553 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2554 766 : pfnProgress, pProgressData, aosOptions.List());
2555 :
2556 766 : if (panAllBandList != nullptr)
2557 753 : CPLFree(panAllBandList);
2558 :
2559 766 : return eErr;
2560 : }
2561 :
2562 : /************************************************************************/
2563 : /* GDALBuildOverviews() */
2564 : /************************************************************************/
2565 :
2566 : /**
2567 : * \brief Build raster overview(s)
2568 : *
2569 : * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2570 : */
2571 :
2572 27 : CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2573 : const char *pszResampling, int nOverviews,
2574 : const int *panOverviewList,
2575 : int nListBands, const int *panBandList,
2576 : GDALProgressFunc pfnProgress,
2577 : void *pProgressData)
2578 :
2579 : {
2580 27 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2581 :
2582 27 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2583 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2584 27 : pfnProgress, pProgressData, nullptr);
2585 : }
2586 :
2587 : /************************************************************************/
2588 : /* GDALBuildOverviews() */
2589 : /************************************************************************/
2590 :
2591 : /**
2592 : * \brief Build raster overview(s)
2593 : *
2594 : * @see GDALDataset::BuildOverviews()
2595 : * @since GDAL 3.6
2596 : */
2597 :
2598 : CPLErr CPL_STDCALL
2599 716 : GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2600 : int nOverviews, const int *panOverviewList, int nListBands,
2601 : const int *panBandList, GDALProgressFunc pfnProgress,
2602 : void *pProgressData, CSLConstList papszOptions)
2603 :
2604 : {
2605 716 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2606 :
2607 716 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2608 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2609 716 : pfnProgress, pProgressData, papszOptions);
2610 : }
2611 :
2612 : /************************************************************************/
2613 : /* IBuildOverviews() */
2614 : /* */
2615 : /* Default implementation. */
2616 : /************************************************************************/
2617 :
2618 : //! @cond Doxygen_Suppress
2619 204 : CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2620 : const int *panOverviewList, int nListBands,
2621 : const int *panBandList,
2622 : GDALProgressFunc pfnProgress,
2623 : void *pProgressData,
2624 : CSLConstList papszOptions)
2625 :
2626 : {
2627 204 : if (oOvManager.IsInitialized())
2628 203 : return oOvManager.BuildOverviews(
2629 : nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2630 203 : panBandList, pfnProgress, pProgressData, papszOptions);
2631 : else
2632 : {
2633 1 : ReportError(CE_Failure, CPLE_NotSupported,
2634 : "BuildOverviews() not supported for this dataset.");
2635 :
2636 1 : return CE_Failure;
2637 : }
2638 : }
2639 :
2640 : //! @endcond
2641 :
2642 : /************************************************************************/
2643 : /* AddOverviews() */
2644 : /* */
2645 : /* Default implementation. */
2646 : /************************************************************************/
2647 :
2648 : /**
2649 : * \brief Add overview from existing dataset(s)
2650 : *
2651 : * This function creates new overview levels or refresh existing one from
2652 : * the list of provided overview datasets.
2653 : * Source overviews may come from any GDAL supported format, provided they
2654 : * have the same number of bands and geospatial extent than the target
2655 : * dataset.
2656 : *
2657 : * If the operation is not supported for the indicated dataset, then
2658 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2659 : * CPLE_NotSupported.
2660 : *
2661 : * At time of writing, this method is only implemented for internal overviews
2662 : * of GeoTIFF datasets and external overviews in GeoTIFF format.
2663 : *
2664 : * @param apoSrcOvrDS Vector of source overviews.
2665 : * @param pfnProgress a function to call to report progress, or NULL.
2666 : * @param pProgressData application data to pass to the progress function.
2667 : * @param papszOptions NULL terminated list of options as
2668 : * key=value pairs, or NULL. Possible keys are the
2669 : * ones returned by
2670 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2671 : *
2672 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2673 : * @since 3.12
2674 : */
2675 5 : CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2676 : GDALProgressFunc pfnProgress,
2677 : void *pProgressData, CSLConstList papszOptions)
2678 : {
2679 5 : if (oOvManager.IsInitialized())
2680 : {
2681 4 : return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2682 4 : pProgressData, papszOptions);
2683 : }
2684 : else
2685 : {
2686 1 : ReportError(CE_Failure, CPLE_NotSupported,
2687 : "AddOverviews() not supported for this dataset.");
2688 1 : return CE_Failure;
2689 : }
2690 : }
2691 :
2692 : /************************************************************************/
2693 : /* IRasterIO() */
2694 : /* */
2695 : /* The default implementation of IRasterIO() is, in the general */
2696 : /* case to pass the request off to each band objects rasterio */
2697 : /* methods with appropriate arguments. In some cases, it might */
2698 : /* choose instead the BlockBasedRasterIO() implementation. */
2699 : /************************************************************************/
2700 :
2701 : //! @cond Doxygen_Suppress
2702 452129 : CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2703 : int nXSize, int nYSize, void *pData,
2704 : int nBufXSize, int nBufYSize,
2705 : GDALDataType eBufType, int nBandCount,
2706 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2707 : GSpacing nLineSpace, GSpacing nBandSpace,
2708 : GDALRasterIOExtraArg *psExtraArg)
2709 :
2710 : {
2711 452129 : const char *pszInterleave = nullptr;
2712 :
2713 452129 : CPLAssert(nullptr != pData);
2714 :
2715 452129 : const bool bHasSubpixelShift =
2716 459320 : psExtraArg->bFloatingPointWindowValidity &&
2717 457674 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2718 5545 : (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2719 :
2720 452010 : if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2721 72552 : nBandCount > 1 &&
2722 72552 : (pszInterleave = GetMetadataItem(
2723 976691 : GDALMD_INTERLEAVE, GDAL_MDD_IMAGE_STRUCTURE)) != nullptr &&
2724 69350 : EQUAL(pszInterleave, "PIXEL"))
2725 : {
2726 65922 : return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2727 : nBufXSize, nBufYSize, eBufType, nBandCount,
2728 : panBandMap, nPixelSpace, nLineSpace,
2729 65922 : nBandSpace, psExtraArg);
2730 : }
2731 :
2732 386207 : if (eRWFlag == GF_Read &&
2733 206517 : (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2734 205722 : psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2735 205709 : psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2736 206517 : psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2737 2521 : !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2738 : {
2739 2475 : if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2740 : {
2741 2264 : int bTried = FALSE;
2742 2264 : const CPLErr eErr = TryOverviewRasterIO(
2743 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2744 : nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2745 : nLineSpace, nBandSpace, psExtraArg, &bTried);
2746 2264 : if (bTried)
2747 1 : return eErr;
2748 : }
2749 :
2750 2474 : GDALDataType eFirstBandDT = GDT_Unknown;
2751 2474 : int nFirstMaskFlags = 0;
2752 2474 : GDALRasterBand *poFirstMaskBand = nullptr;
2753 2474 : int nOKBands = 0;
2754 :
2755 : // Check if bands share the same mask band
2756 9095 : for (int i = 0; i < nBandCount; ++i)
2757 : {
2758 8820 : GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2759 16965 : if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2760 8145 : poBand->GetOverviewCount())
2761 : {
2762 : // Could be improved to select the appropriate overview.
2763 3 : break;
2764 : }
2765 8817 : if (poBand->GetColorTable() != nullptr)
2766 : {
2767 0 : break;
2768 : }
2769 8817 : const GDALDataType eDT = poBand->GetRasterDataType();
2770 8817 : if (GDALDataTypeIsComplex(eDT))
2771 : {
2772 30 : break;
2773 : }
2774 8787 : if (i == 0)
2775 : {
2776 2441 : eFirstBandDT = eDT;
2777 2441 : nFirstMaskFlags = poBand->GetMaskFlags();
2778 2441 : if (nFirstMaskFlags == GMF_NODATA)
2779 : {
2780 : // The dataset-level resampling code is not ready for nodata
2781 : // Fallback to band-level resampling
2782 10 : break;
2783 : }
2784 2431 : poFirstMaskBand = poBand->GetMaskBand();
2785 : }
2786 : else
2787 : {
2788 6346 : if (eDT != eFirstBandDT)
2789 : {
2790 0 : break;
2791 : }
2792 6346 : int nMaskFlags = poBand->GetMaskFlags();
2793 6346 : if (nMaskFlags == GMF_NODATA)
2794 : {
2795 : // The dataset-level resampling code is not ready for nodata
2796 : // Fallback to band-level resampling
2797 0 : break;
2798 : }
2799 6346 : GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2800 6346 : if (nFirstMaskFlags == GMF_ALL_VALID &&
2801 : nMaskFlags == GMF_ALL_VALID)
2802 : {
2803 : // Ok.
2804 : }
2805 5694 : else if (poFirstMaskBand == poMaskBand)
2806 : {
2807 : // Ok.
2808 : }
2809 : else
2810 : {
2811 2156 : break;
2812 : }
2813 : }
2814 :
2815 6621 : ++nOKBands;
2816 : }
2817 :
2818 2474 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2819 2474 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2820 :
2821 2474 : CPLErr eErr = CE_None;
2822 2474 : if (nOKBands > 0)
2823 : {
2824 2431 : if (nOKBands < nBandCount)
2825 : {
2826 2156 : psExtraArg->pfnProgress = GDALScaledProgress;
2827 4312 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2828 2156 : 0.0, static_cast<double>(nOKBands) / nBandCount,
2829 : pfnProgressGlobal, pProgressDataGlobal);
2830 2156 : if (psExtraArg->pProgressData == nullptr)
2831 231 : psExtraArg->pfnProgress = nullptr;
2832 : }
2833 :
2834 2431 : eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2835 : pData, nBufXSize, nBufYSize, eBufType,
2836 : nOKBands, panBandMap, nPixelSpace,
2837 : nLineSpace, nBandSpace, psExtraArg);
2838 :
2839 2431 : if (nOKBands < nBandCount)
2840 : {
2841 2156 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2842 : }
2843 : }
2844 2474 : if (eErr == CE_None && nOKBands < nBandCount)
2845 : {
2846 2196 : if (nOKBands > 0)
2847 : {
2848 2153 : psExtraArg->pfnProgress = GDALScaledProgress;
2849 4306 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2850 2153 : static_cast<double>(nOKBands) / nBandCount, 1.0,
2851 : pfnProgressGlobal, pProgressDataGlobal);
2852 2153 : if (psExtraArg->pProgressData == nullptr)
2853 228 : psExtraArg->pfnProgress = nullptr;
2854 : }
2855 4392 : eErr = BandBasedRasterIO(
2856 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
2857 2196 : static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2858 : nBufYSize, eBufType, nBandCount - nOKBands,
2859 2196 : panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2860 : psExtraArg);
2861 2196 : if (nOKBands > 0)
2862 : {
2863 2153 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2864 : }
2865 : }
2866 :
2867 2474 : psExtraArg->pfnProgress = pfnProgressGlobal;
2868 2474 : psExtraArg->pProgressData = pProgressDataGlobal;
2869 :
2870 2474 : return eErr;
2871 : }
2872 :
2873 383732 : return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2874 : nBufXSize, nBufYSize, eBufType, nBandCount,
2875 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2876 383732 : psExtraArg);
2877 : }
2878 :
2879 : //! @endcond
2880 :
2881 : /************************************************************************/
2882 : /* BandBasedRasterIO() */
2883 : /* */
2884 : /* Pass the request off to each band objects rasterio methods with */
2885 : /* appropriate arguments. */
2886 : /************************************************************************/
2887 :
2888 : //! @cond Doxygen_Suppress
2889 662265 : CPLErr GDALDataset::BandBasedRasterIO(
2890 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2891 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2892 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2893 : GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2894 :
2895 : {
2896 : int iBandIndex;
2897 662265 : CPLErr eErr = CE_None;
2898 :
2899 662265 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2900 662265 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2901 :
2902 1726220 : for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2903 : ++iBandIndex)
2904 : {
2905 1063960 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2906 :
2907 1063960 : if (poBand == nullptr)
2908 : {
2909 0 : eErr = CE_Failure;
2910 0 : break;
2911 : }
2912 :
2913 1063960 : GByte *pabyBandData =
2914 1063960 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2915 :
2916 1063960 : if (nBandCount > 1)
2917 : {
2918 592065 : psExtraArg->pfnProgress = GDALScaledProgress;
2919 1184130 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2920 : 1.0 * iBandIndex / nBandCount,
2921 592065 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2922 : pProgressDataGlobal);
2923 592065 : if (psExtraArg->pProgressData == nullptr)
2924 578466 : psExtraArg->pfnProgress = nullptr;
2925 : }
2926 :
2927 2127920 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2928 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2929 1063960 : nPixelSpace, nLineSpace, psExtraArg);
2930 :
2931 1063960 : if (nBandCount > 1)
2932 592065 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2933 : }
2934 :
2935 662265 : psExtraArg->pfnProgress = pfnProgressGlobal;
2936 662265 : psExtraArg->pProgressData = pProgressDataGlobal;
2937 :
2938 662265 : return eErr;
2939 : }
2940 :
2941 : //! @endcond
2942 :
2943 : /************************************************************************/
2944 : /* ValidateRasterIOOrAdviseReadParameters() */
2945 : /************************************************************************/
2946 :
2947 : //! @cond Doxygen_Suppress
2948 770920 : CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2949 : const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2950 : int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2951 : int nBandCount, const int *panBandMap)
2952 : {
2953 770920 : if (nBands == 0)
2954 : {
2955 140 : *pbStopProcessingOnCENone = TRUE;
2956 140 : return CE_None;
2957 : }
2958 :
2959 : /* -------------------------------------------------------------------- */
2960 : /* Some size values are "noop". Lets just return to avoid */
2961 : /* stressing lower level functions. */
2962 : /* -------------------------------------------------------------------- */
2963 770780 : if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2964 : {
2965 9 : CPLDebug("GDAL",
2966 : "%s skipped for odd window or buffer size.\n"
2967 : " Window = (%d,%d)x%dx%d\n"
2968 : " Buffer = %dx%d",
2969 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2970 : nBufYSize);
2971 :
2972 9 : *pbStopProcessingOnCENone = TRUE;
2973 9 : return CE_None;
2974 : }
2975 :
2976 770771 : CPLErr eErr = CE_None;
2977 770771 : *pbStopProcessingOnCENone = FALSE;
2978 :
2979 770771 : if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2980 770769 : nYSize > nRasterYSize - nYOff)
2981 : {
2982 2 : ReportError(CE_Failure, CPLE_IllegalArg,
2983 : "Access window out of range in %s. Requested "
2984 : "(%d,%d) of size %dx%d on raster of %dx%d.",
2985 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2986 : nRasterYSize);
2987 2 : eErr = CE_Failure;
2988 : }
2989 :
2990 770771 : if (panBandMap == nullptr && nBandCount > GetRasterCount())
2991 : {
2992 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2993 : "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2994 : GetRasterCount());
2995 0 : eErr = CE_Failure;
2996 : }
2997 :
2998 2336390 : for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2999 : {
3000 1565620 : int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
3001 1565620 : if (iBand < 1 || iBand > GetRasterCount())
3002 : {
3003 3 : ReportError(
3004 : CE_Failure, CPLE_IllegalArg,
3005 : "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
3006 : pszCallingFunc, i, iBand);
3007 3 : eErr = CE_Failure;
3008 : }
3009 :
3010 1565620 : if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3011 : {
3012 0 : ReportError(
3013 : CE_Failure, CPLE_IllegalArg,
3014 : "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3015 : pszCallingFunc, i, iBand);
3016 0 : eErr = CE_Failure;
3017 : }
3018 : }
3019 :
3020 770771 : return eErr;
3021 : }
3022 :
3023 : //! @endcond
3024 :
3025 : /************************************************************************/
3026 : /* RasterIO() */
3027 : /************************************************************************/
3028 :
3029 : /**
3030 : * \brief Read/write a region of image data from multiple bands.
3031 : *
3032 : * This method allows reading a region of one or more GDALRasterBands from
3033 : * this dataset into a buffer, or writing data from a buffer into a region
3034 : * of the GDALRasterBands. It automatically takes care of data type
3035 : * translation if the data type (eBufType) of the buffer is different than
3036 : * that of the GDALRasterBand.
3037 : * The method also takes care of image decimation / replication if the
3038 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
3039 : * region being accessed (nXSize x nYSize).
3040 : *
3041 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3042 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3043 : * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3044 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
3045 : * Or use nLineSpace and a possibly shifted pData value.
3046 : *
3047 : * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3048 : * writing from various organization of buffers.
3049 : *
3050 : * Some formats may efficiently implement decimation into a buffer by
3051 : * reading from lower resolution overview images. The logic of the default
3052 : * implementation in the base class GDALRasterBand is the following one. It
3053 : * computes a target_downscaling_factor from the window of interest and buffer
3054 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3055 : * It then walks through overviews and will select the first one whose
3056 : * downscaling factor is greater than target_downscaling_factor / 1.2.
3057 : *
3058 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3059 : * The relationship between target_downscaling_factor and the select overview
3060 : * level is the following one:
3061 : *
3062 : * target_downscaling_factor | selected_overview
3063 : * ------------------------- | -----------------
3064 : * ]0, 2 / 1.2] | full resolution band
3065 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
3066 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
3067 : * ]8 / 1.2, infinity[ | 8x downsampled band
3068 : *
3069 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3070 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3071 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3072 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3073 : * this oversampling threshold defaults to 1. Consequently if there are overviews
3074 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3075 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3076 : *
3077 : * For highest performance full resolution data access, read and write
3078 : * on "block boundaries" as returned by GetBlockSize(), or use the
3079 : * ReadBlock() and WriteBlock() methods.
3080 : *
3081 : * This method is the same as the C GDALDatasetRasterIO() or
3082 : * GDALDatasetRasterIOEx() functions.
3083 : *
3084 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3085 : * write a region of data.
3086 : *
3087 : * @param nXOff The pixel offset to the top left corner of the region
3088 : * of the band to be accessed. This would be zero to start from the left side.
3089 : *
3090 : * @param nYOff The line offset to the top left corner of the region
3091 : * of the band to be accessed. This would be zero to start from the top.
3092 : *
3093 : * @param nXSize The width of the region of the band to be accessed in pixels.
3094 : *
3095 : * @param nYSize The height of the region of the band to be accessed in lines.
3096 : *
3097 : * @param pData The buffer into which the data should be read, or from which
3098 : * it should be written. This buffer must contain at least
3099 : * nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized
3100 : * in left to right,top to bottom pixel order. Spacing is controlled by the
3101 : * nPixelSpace, and nLineSpace parameters.
3102 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3103 : * temporarily modified during the execution of this method (and eventually
3104 : * restored back to its original content), so it is not safe to use a buffer
3105 : * stored in a read-only section of the calling program.
3106 : *
3107 : * @param nBufXSize the width of the buffer image into which the desired region
3108 : * is to be read, or from which it is to be written.
3109 : *
3110 : * @param nBufYSize the height of the buffer image into which the desired
3111 : * region is to be read, or from which it is to be written.
3112 : *
3113 : * @param eBufType the type of the pixel values in the pData data buffer. The
3114 : * pixel values will automatically be translated to/from the GDALRasterBand
3115 : * data type as needed. Most driver implementations will use GDALCopyWords64()
3116 : * to perform data type translation.
3117 : *
3118 : * @param nBandCount the number of bands being read or written.
3119 : *
3120 : * @param panBandMap the list of nBandCount band numbers being read/written.
3121 : * Note band numbers are 1 based. This may be NULL to select the first
3122 : * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3123 : * not "const int*")
3124 : *
3125 : * @param nPixelSpace The byte offset from the start of one pixel value in
3126 : * pData to the start of the next pixel value within a scanline. If defaulted
3127 : * (0) the size of the datatype eBufType is used.
3128 : *
3129 : * @param nLineSpace The byte offset from the start of one scanline in
3130 : * pData to the start of the next. If defaulted (0) the size of the datatype
3131 : * eBufType * nBufXSize is used.
3132 : *
3133 : * @param nBandSpace the byte offset from the start of one bands data to the
3134 : * start of the next. If defaulted (0) the value will be
3135 : * nLineSpace * nBufYSize implying band sequential organization
3136 : * of the data buffer.
3137 : *
3138 : * @param psExtraArg pointer to a GDALRasterIOExtraArg
3139 : * structure with additional arguments to specify resampling and progress
3140 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3141 : * configuration option can also be defined to override the default resampling
3142 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3143 : *
3144 : * @return CE_Failure if the access fails, otherwise CE_None.
3145 : */
3146 :
3147 755155 : CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3148 : int nXSize, int nYSize, void *pData, int nBufXSize,
3149 : int nBufYSize, GDALDataType eBufType,
3150 : int nBandCount, const int *panBandMap,
3151 : GSpacing nPixelSpace, GSpacing nLineSpace,
3152 : GSpacing nBandSpace,
3153 : GDALRasterIOExtraArg *psExtraArg)
3154 :
3155 : {
3156 : GDALRasterIOExtraArg sExtraArg;
3157 755155 : if (psExtraArg == nullptr)
3158 : {
3159 555324 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3160 :
3161 : // 4 below inits are not strictly needed but make Coverity Scan
3162 : // happy
3163 555324 : sExtraArg.dfXOff = nXOff;
3164 555324 : sExtraArg.dfYOff = nYOff;
3165 555324 : sExtraArg.dfXSize = nXSize;
3166 555324 : sExtraArg.dfYSize = nYSize;
3167 :
3168 555324 : psExtraArg = &sExtraArg;
3169 : }
3170 199831 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
3171 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3172 : {
3173 0 : ReportError(CE_Failure, CPLE_AppDefined,
3174 : "Unhandled version of GDALRasterIOExtraArg");
3175 0 : return CE_Failure;
3176 : }
3177 :
3178 755155 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3179 : nBufYSize);
3180 :
3181 755155 : if (CPL_UNLIKELY(nullptr == pData))
3182 : {
3183 0 : ReportError(CE_Failure, CPLE_AppDefined,
3184 : "The buffer into which the data should be read is null");
3185 0 : return CE_Failure;
3186 : }
3187 :
3188 : /* -------------------------------------------------------------------- */
3189 : /* Do some validation of parameters. */
3190 : /* -------------------------------------------------------------------- */
3191 :
3192 755155 : if (CPL_UNLIKELY(static_cast<int>(eRWFlag) != static_cast<int>(GF_Read) &&
3193 : static_cast<int>(eRWFlag) != static_cast<int>(GF_Write)))
3194 : {
3195 0 : ReportError(
3196 : CE_Failure, CPLE_IllegalArg,
3197 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3198 : eRWFlag);
3199 0 : return CE_Failure;
3200 : }
3201 :
3202 755155 : if (eRWFlag == GF_Write)
3203 : {
3204 216821 : if (CPL_UNLIKELY(eAccess != GA_Update))
3205 : {
3206 3 : ReportError(CE_Failure, CPLE_AppDefined,
3207 : "Write operation not permitted on dataset opened "
3208 : "in read-only mode");
3209 3 : return CE_Failure;
3210 : }
3211 : }
3212 :
3213 755152 : int bStopProcessing = FALSE;
3214 755152 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3215 : "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3216 : nBufYSize, nBandCount, panBandMap);
3217 755152 : if (eErr != CE_None || bStopProcessing)
3218 9 : return eErr;
3219 755143 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3220 : {
3221 2 : ReportError(CE_Failure, CPLE_AppDefined,
3222 : "Illegal GDT_Unknown/GDT_TypeCount argument");
3223 2 : return CE_Failure;
3224 : }
3225 :
3226 : /* -------------------------------------------------------------------- */
3227 : /* If pixel and line spacing are defaulted assign reasonable */
3228 : /* value assuming a packed buffer. */
3229 : /* -------------------------------------------------------------------- */
3230 755141 : if (nPixelSpace == 0)
3231 426685 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3232 :
3233 755141 : if (nLineSpace == 0)
3234 : {
3235 484000 : nLineSpace = nPixelSpace * nBufXSize;
3236 : }
3237 :
3238 755141 : if (nBandSpace == 0 && nBandCount > 1)
3239 : {
3240 68424 : nBandSpace = nLineSpace * nBufYSize;
3241 : }
3242 :
3243 755141 : if (panBandMap == nullptr)
3244 : {
3245 371948 : if (!m_poPrivate)
3246 0 : return CE_Failure;
3247 371948 : CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3248 371948 : panBandMap = m_poPrivate->m_anBandMap.data();
3249 : }
3250 :
3251 755141 : int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3252 :
3253 : /* -------------------------------------------------------------------- */
3254 : /* We are being forced to use cached IO instead of a driver */
3255 : /* specific implementation. */
3256 : /* -------------------------------------------------------------------- */
3257 755141 : if (bForceCachedIO)
3258 : {
3259 21 : eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3260 : nBufXSize, nBufYSize, eBufType, nBandCount,
3261 : panBandMap, nPixelSpace, nLineSpace,
3262 21 : nBandSpace, psExtraArg);
3263 : }
3264 :
3265 : /* -------------------------------------------------------------------- */
3266 : /* Call the format specific function. */
3267 : /* -------------------------------------------------------------------- */
3268 : else
3269 : {
3270 755120 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3271 : nBufXSize, nBufYSize, eBufType, nBandCount,
3272 : // TODO: remove this const_cast once IRasterIO()
3273 : // takes a const int*
3274 : const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3275 755120 : nBandSpace, psExtraArg);
3276 : }
3277 :
3278 755141 : if (bCallLeaveReadWrite)
3279 416410 : LeaveReadWrite();
3280 :
3281 755141 : return eErr;
3282 : }
3283 :
3284 : /************************************************************************/
3285 : /* GDALDatasetRasterIO() */
3286 : /************************************************************************/
3287 :
3288 : /**
3289 : * \brief Read/write a region of image data from multiple bands.
3290 : *
3291 : * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3292 : * resolution, progress callback, etc. are needed)
3293 : *
3294 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3295 : *
3296 : * @see GDALDataset::RasterIO()
3297 : */
3298 :
3299 4841 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3300 : int nXOff, int nYOff, int nXSize,
3301 : int nYSize, void *pData, int nBufXSize,
3302 : int nBufYSize, GDALDataType eBufType,
3303 : int nBandCount, const int *panBandMap,
3304 : int nPixelSpace, int nLineSpace,
3305 : int nBandSpace)
3306 :
3307 : {
3308 4841 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3309 :
3310 4841 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3311 :
3312 4841 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3313 : nBufXSize, nBufYSize, eBufType, nBandCount,
3314 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3315 4841 : nullptr);
3316 : }
3317 :
3318 : /************************************************************************/
3319 : /* GDALDatasetRasterIOEx() */
3320 : /************************************************************************/
3321 :
3322 : /**
3323 : * \brief Read/write a region of image data from multiple bands.
3324 : *
3325 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3326 : *
3327 : * @see GDALDataset::RasterIO()
3328 : */
3329 :
3330 353731 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3331 : GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3332 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
3333 : GDALDataType eBufType, int nBandCount, const int *panBandMap,
3334 : GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3335 : GDALRasterIOExtraArg *psExtraArg)
3336 :
3337 : {
3338 353731 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3339 :
3340 353731 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3341 :
3342 353731 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3343 : nBufXSize, nBufYSize, eBufType, nBandCount,
3344 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3345 353731 : psExtraArg);
3346 : }
3347 :
3348 : /************************************************************************/
3349 : /* GetOpenDatasets() */
3350 : /************************************************************************/
3351 :
3352 : /**
3353 : * \brief Fetch all open GDAL dataset handles.
3354 : *
3355 : * This method is the same as the C function GDALGetOpenDatasets().
3356 : *
3357 : * NOTE: This method is not thread safe. The returned list may change
3358 : * at any time and it should not be freed.
3359 : *
3360 : * @param pnCount integer into which to place the count of dataset pointers
3361 : * being returned.
3362 : *
3363 : * @return a pointer to an array of dataset handles.
3364 : */
3365 :
3366 2618 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3367 :
3368 : {
3369 5236 : CPLMutexHolderD(&hDLMutex);
3370 :
3371 2618 : if (poAllDatasetMap == nullptr)
3372 : {
3373 2596 : *pnCount = 0;
3374 2596 : return nullptr;
3375 : }
3376 :
3377 22 : *pnCount = static_cast<int>(poAllDatasetMap->size());
3378 22 : ppDatasets = static_cast<GDALDataset **>(
3379 22 : CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3380 22 : std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3381 622 : for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3382 600 : ppDatasets[i] = oIter->first;
3383 22 : return ppDatasets;
3384 : }
3385 :
3386 : /************************************************************************/
3387 : /* GDALGetOpenDatasets() */
3388 : /************************************************************************/
3389 :
3390 : /**
3391 : * \brief Fetch all open GDAL dataset handles.
3392 : *
3393 : * @see GDALDataset::GetOpenDatasets()
3394 : */
3395 :
3396 0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3397 :
3398 : {
3399 0 : VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3400 0 : VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3401 :
3402 0 : *ppahDSList =
3403 0 : reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3404 : }
3405 :
3406 : /************************************************************************/
3407 : /* GDALCleanOpenDatasetsList() */
3408 : /************************************************************************/
3409 :
3410 : // Useful when called from the child of a fork(), to avoid closing
3411 : // the datasets of the parent at the child termination.
3412 0 : void GDALNullifyOpenDatasetsList()
3413 : {
3414 0 : poAllDatasetMap = nullptr;
3415 0 : phSharedDatasetSet = nullptr;
3416 0 : ppDatasets = nullptr;
3417 0 : hDLMutex = nullptr;
3418 0 : }
3419 :
3420 : /************************************************************************/
3421 : /* GDALGetAccess() */
3422 : /************************************************************************/
3423 :
3424 : /**
3425 : * \brief Return access flag
3426 : *
3427 : * @see GDALDataset::GetAccess()
3428 : */
3429 :
3430 1 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3431 : {
3432 1 : VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3433 :
3434 1 : return GDALDataset::FromHandle(hDS)->GetAccess();
3435 : }
3436 :
3437 : /************************************************************************/
3438 : /* AdviseRead() */
3439 : /************************************************************************/
3440 :
3441 : /**
3442 : * \brief Advise driver of upcoming read requests.
3443 : *
3444 : * Some GDAL drivers operate more efficiently if they know in advance what
3445 : * set of upcoming read requests will be made. The AdviseRead() method allows
3446 : * an application to notify the driver of the region and bands of interest,
3447 : * and at what resolution the region will be read.
3448 : *
3449 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
3450 : * accelerate access via some drivers.
3451 : *
3452 : * Depending on call paths, drivers might receive several calls to
3453 : * AdviseRead() with the same parameters.
3454 : *
3455 : * @param nXOff The pixel offset to the top left corner of the region
3456 : * of the band to be accessed. This would be zero to start from the left side.
3457 : *
3458 : * @param nYOff The line offset to the top left corner of the region
3459 : * of the band to be accessed. This would be zero to start from the top.
3460 : *
3461 : * @param nXSize The width of the region of the band to be accessed in pixels.
3462 : *
3463 : * @param nYSize The height of the region of the band to be accessed in lines.
3464 : *
3465 : * @param nBufXSize the width of the buffer image into which the desired region
3466 : * is to be read, or from which it is to be written.
3467 : *
3468 : * @param nBufYSize the height of the buffer image into which the desired
3469 : * region is to be read, or from which it is to be written.
3470 : *
3471 : * @param eBufType the type of the pixel values in the pData data buffer. The
3472 : * pixel values will automatically be translated to/from the GDALRasterBand
3473 : * data type as needed.
3474 : *
3475 : * @param nBandCount the number of bands being read or written.
3476 : *
3477 : * @param panBandMap the list of nBandCount band numbers being read/written.
3478 : * Note band numbers are 1 based. This may be NULL to select the first
3479 : * nBandCount bands.
3480 : *
3481 : * @param papszOptions a list of name=value strings with special control
3482 : * options. Normally this is NULL.
3483 : *
3484 : * @return CE_Failure if the request is invalid and CE_None if it works or
3485 : * is ignored.
3486 : */
3487 :
3488 15474 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3489 : int nBufXSize, int nBufYSize,
3490 : GDALDataType eBufType, int nBandCount,
3491 : int *panBandMap, CSLConstList papszOptions)
3492 :
3493 : {
3494 : /* -------------------------------------------------------------------- */
3495 : /* Do some validation of parameters. */
3496 : /* -------------------------------------------------------------------- */
3497 15474 : int bStopProcessing = FALSE;
3498 15474 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3499 : "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3500 : nBufXSize, nBufYSize, nBandCount, panBandMap);
3501 15474 : if (eErr != CE_None || bStopProcessing)
3502 145 : return eErr;
3503 :
3504 130396 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3505 : {
3506 115071 : GDALRasterBand *poBand = nullptr;
3507 :
3508 115071 : if (panBandMap == nullptr)
3509 113546 : poBand = GetRasterBand(iBand + 1);
3510 : else
3511 1525 : poBand = GetRasterBand(panBandMap[iBand]);
3512 :
3513 115071 : if (poBand == nullptr)
3514 0 : return CE_Failure;
3515 :
3516 230142 : eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3517 115071 : nBufYSize, eBufType, papszOptions);
3518 :
3519 115071 : if (eErr != CE_None)
3520 4 : return eErr;
3521 : }
3522 :
3523 15325 : return CE_None;
3524 : }
3525 :
3526 : /************************************************************************/
3527 : /* GDALDatasetAdviseRead() */
3528 : /************************************************************************/
3529 :
3530 : /**
3531 : * \brief Advise driver of upcoming read requests.
3532 : *
3533 : * @see GDALDataset::AdviseRead()
3534 : */
3535 7 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3536 : int nXSize, int nYSize, int nBufXSize,
3537 : int nBufYSize, GDALDataType eDT,
3538 : int nBandCount, int *panBandMap,
3539 : CSLConstList papszOptions)
3540 :
3541 : {
3542 7 : VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3543 :
3544 14 : return GDALDataset::FromHandle(hDS)->AdviseRead(
3545 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3546 7 : panBandMap, const_cast<char **>(papszOptions));
3547 : }
3548 :
3549 : /************************************************************************/
3550 : /* GDALAntiRecursionStruct */
3551 : /************************************************************************/
3552 :
3553 : // Prevent infinite recursion.
3554 : struct GDALAntiRecursionStruct
3555 : {
3556 : struct DatasetContext
3557 : {
3558 : std::string osFilename;
3559 : int nOpenFlags;
3560 : std::string osAllowedDrivers;
3561 :
3562 87913 : DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3563 : const std::string &osAllowedDriversIn)
3564 87913 : : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3565 87913 : osAllowedDrivers(osAllowedDriversIn)
3566 : {
3567 87913 : }
3568 : };
3569 :
3570 : struct DatasetContextCompare
3571 : {
3572 1213010 : bool operator()(const DatasetContext &lhs,
3573 : const DatasetContext &rhs) const
3574 : {
3575 3580340 : return lhs.osFilename < rhs.osFilename ||
3576 1189250 : (lhs.osFilename == rhs.osFilename &&
3577 1178080 : (lhs.nOpenFlags < rhs.nOpenFlags ||
3578 2339670 : (lhs.nOpenFlags == rhs.nOpenFlags &&
3579 2380790 : lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3580 : }
3581 : };
3582 :
3583 1453 : ~GDALAntiRecursionStruct()
3584 1453 : {
3585 1453 : CPLAssert(aosDatasetNamesWithFlags.empty());
3586 1453 : CPLAssert(nRecLevel == 0);
3587 1453 : CPLAssert(m_oMapDepth.empty());
3588 1453 : }
3589 :
3590 : std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3591 : int nRecLevel = 0;
3592 : std::map<std::string, int> m_oMapDepth{};
3593 : };
3594 :
3595 : #ifdef _WIN32
3596 : // Currently thread_local and C++ objects don't work well with DLL on Windows
3597 : static void FreeAntiRecursionOpen(void *pData)
3598 : {
3599 : delete static_cast<GDALAntiRecursionStruct *>(pData);
3600 : }
3601 :
3602 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3603 : {
3604 : static GDALAntiRecursionStruct dummy;
3605 : int bMemoryErrorOccurred = false;
3606 : void *pData =
3607 : CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3608 : if (bMemoryErrorOccurred)
3609 : {
3610 : return dummy;
3611 : }
3612 : if (pData == nullptr)
3613 : {
3614 : auto pAntiRecursion = new GDALAntiRecursionStruct();
3615 : CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3616 : FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3617 : if (bMemoryErrorOccurred)
3618 : {
3619 : delete pAntiRecursion;
3620 : return dummy;
3621 : }
3622 : return *pAntiRecursion;
3623 : }
3624 : return *static_cast<GDALAntiRecursionStruct *>(pData);
3625 : }
3626 : #else
3627 : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3628 :
3629 387834 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3630 : {
3631 387834 : return g_tls_antiRecursion;
3632 : }
3633 : #endif
3634 :
3635 : //! @cond Doxygen_Suppress
3636 299921 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3637 299921 : : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3638 : m_osIdentifier(osIdentifier),
3639 299921 : m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3640 : {
3641 299921 : CPLAssert(!osIdentifier.empty());
3642 299921 : }
3643 :
3644 299921 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3645 299921 : const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3646 299921 : : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3647 299921 : m_osIdentifier(osIdentifier.empty()
3648 : ? osIdentifier
3649 31170 : : other.m_osIdentifier + osIdentifier),
3650 299921 : m_nDepth(m_osIdentifier.empty()
3651 299921 : ? 0
3652 331091 : : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3653 : {
3654 299921 : }
3655 :
3656 599842 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3657 : {
3658 599842 : if (!m_osIdentifier.empty())
3659 : {
3660 331091 : auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3661 331091 : CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3662 331091 : if (--(oIter->second) == 0)
3663 326796 : m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3664 : }
3665 599842 : }
3666 :
3667 : //! @endcond
3668 :
3669 : /************************************************************************/
3670 : /* GetFileList() */
3671 : /************************************************************************/
3672 :
3673 : /**
3674 : * \brief Fetch files forming dataset.
3675 : *
3676 : * Returns a list of files believed to be part of this dataset. If it returns
3677 : * an empty list of files it means there is believed to be no local file
3678 : * system files associated with the dataset (for instance a virtual dataset).
3679 : * The returned file list is owned by the caller and should be deallocated
3680 : * with CSLDestroy().
3681 : *
3682 : * The returned filenames will normally be relative or absolute paths
3683 : * depending on the path used to originally open the dataset. The strings
3684 : * will be UTF-8 encoded.
3685 : *
3686 : * This method is the same as the C GDALGetFileList() function.
3687 : *
3688 : * @return NULL or a NULL terminated array of file names.
3689 : */
3690 :
3691 4721 : char **GDALDataset::GetFileList()
3692 :
3693 : {
3694 9442 : CPLString osMainFilename = GetDescription();
3695 : VSIStatBufL sStat;
3696 :
3697 4721 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3698 : GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3699 9442 : std::string());
3700 4721 : auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3701 4721 : if (cpl::contains(aosDatasetList, datasetCtxt))
3702 0 : return nullptr;
3703 :
3704 : /* -------------------------------------------------------------------- */
3705 : /* Is the main filename even a real filesystem object? */
3706 : /* -------------------------------------------------------------------- */
3707 : int bMainFileReal =
3708 4721 : VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3709 :
3710 : /* -------------------------------------------------------------------- */
3711 : /* Form new list. */
3712 : /* -------------------------------------------------------------------- */
3713 4721 : char **papszList = nullptr;
3714 :
3715 4721 : if (bMainFileReal)
3716 4641 : papszList = CSLAddString(papszList, osMainFilename);
3717 :
3718 4721 : if (sAntiRecursion.nRecLevel == 100)
3719 : {
3720 0 : CPLError(CE_Failure, CPLE_AppDefined,
3721 : "GetFileList() called with too many recursion levels");
3722 0 : return papszList;
3723 : }
3724 4721 : ++sAntiRecursion.nRecLevel;
3725 :
3726 : /* -------------------------------------------------------------------- */
3727 : /* Do we have a known overview file? */
3728 : /* -------------------------------------------------------------------- */
3729 4721 : if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3730 : {
3731 59 : auto iter = aosDatasetList.insert(datasetCtxt).first;
3732 59 : char **papszOvrList = oOvManager.poODS->GetFileList();
3733 59 : papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3734 59 : CSLDestroy(papszOvrList);
3735 59 : aosDatasetList.erase(iter);
3736 : }
3737 :
3738 : /* -------------------------------------------------------------------- */
3739 : /* Do we have a known mask file? */
3740 : /* -------------------------------------------------------------------- */
3741 4721 : if (oOvManager.HaveMaskFile())
3742 : {
3743 9 : auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3744 9 : for (const char *pszFile :
3745 18 : CPLStringList(oOvManager.poMaskDS->GetFileList()))
3746 : {
3747 9 : if (CSLFindString(papszList, pszFile) < 0)
3748 9 : papszList = CSLAddString(papszList, pszFile);
3749 : }
3750 9 : aosDatasetList.erase(iter);
3751 : }
3752 :
3753 4721 : --sAntiRecursion.nRecLevel;
3754 :
3755 4721 : return papszList;
3756 : }
3757 :
3758 : /************************************************************************/
3759 : /* GDALGetFileList() */
3760 : /************************************************************************/
3761 :
3762 : /**
3763 : * \brief Fetch files forming dataset.
3764 : *
3765 : * @see GDALDataset::GetFileList()
3766 : */
3767 :
3768 3693 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3769 :
3770 : {
3771 3693 : VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3772 :
3773 3693 : return GDALDataset::FromHandle(hDS)->GetFileList();
3774 : }
3775 :
3776 : /************************************************************************/
3777 : /* CreateMaskBand() */
3778 : /************************************************************************/
3779 :
3780 : /**
3781 : * \brief Adds a mask band to the dataset
3782 : *
3783 : * The default implementation of the CreateMaskBand() method is implemented
3784 : * based on similar rules to the .ovr handling implemented using the
3785 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3786 : * be created with the same basename as the original file, and it will have
3787 : * one band.
3788 : * The mask images will be deflate compressed tiled images with the same
3789 : * block size as the original image if possible.
3790 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3791 : * level, where xx matches the band number of a band of the main dataset. The
3792 : * value of those items will be the one of the nFlagsIn parameter.
3793 : *
3794 : * Note that if you got a mask band with a previous call to GetMaskBand(), it
3795 : * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3796 : * again.
3797 : *
3798 : *
3799 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3800 : * GMF_PER_DATASET will be always set, even if not explicitly
3801 : * specified.
3802 : * @return CE_None on success or CE_Failure on an error.
3803 : *
3804 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3805 : * @see GDALRasterBand::CreateMaskBand()
3806 : *
3807 : */
3808 17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3809 :
3810 : {
3811 17 : if (oOvManager.IsInitialized())
3812 : {
3813 17 : CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3814 17 : if (eErr != CE_None)
3815 0 : return eErr;
3816 :
3817 : // Invalidate existing raster band masks.
3818 45 : for (int i = 0; i < nBands; ++i)
3819 : {
3820 28 : GDALRasterBand *poBand = papoBands[i];
3821 28 : poBand->poMask.reset();
3822 : }
3823 :
3824 17 : return CE_None;
3825 : }
3826 :
3827 0 : ReportError(CE_Failure, CPLE_NotSupported,
3828 : "CreateMaskBand() not supported for this dataset.");
3829 :
3830 0 : return CE_Failure;
3831 : }
3832 :
3833 : /************************************************************************/
3834 : /* GDALCreateDatasetMaskBand() */
3835 : /************************************************************************/
3836 :
3837 : /**
3838 : * \brief Adds a mask band to the dataset
3839 : * @see GDALDataset::CreateMaskBand()
3840 : */
3841 108 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3842 :
3843 : {
3844 108 : VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3845 :
3846 108 : return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3847 : }
3848 :
3849 : /************************************************************************/
3850 : /* GDALOpen() */
3851 : /************************************************************************/
3852 :
3853 : /**
3854 : * \brief Open a raster file as a GDALDataset.
3855 : *
3856 : * This function will try to open the passed file, or virtual dataset
3857 : * name by invoking the Open method of each registered GDALDriver in turn.
3858 : * The first successful open will result in a returned dataset. If all
3859 : * drivers fail then NULL is returned and an error is issued.
3860 : *
3861 : * Several recommendations :
3862 : * <ul>
3863 : * <li>If you open a dataset object with GA_Update access, it is not recommended
3864 : * to open a new dataset on the same underlying file.</li>
3865 : * <li>The returned dataset should only be accessed by one thread at a time. If
3866 : * you want to use it from different threads, you must add all necessary code
3867 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3868 : * as GeoTIFF, maintain internal state variables that are updated each time a
3869 : * new block is read, thus preventing concurrent use.) </li>
3870 : * </ul>
3871 : *
3872 : * For drivers supporting the VSI virtual file API, it is possible to open a
3873 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3874 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3875 : * server (see VSIInstallCurlFileHandler())
3876 : *
3877 : * \sa GDALOpenShared()
3878 : * \sa GDALOpenEx()
3879 : *
3880 : * @param pszFilename the name of the file to access. In the case of
3881 : * exotic drivers this may not refer to a physical file, but instead contain
3882 : * information for the driver on how to access a dataset. It should be in UTF-8
3883 : * encoding.
3884 : *
3885 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
3886 : * drivers support only read only access.
3887 : *
3888 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
3889 : * this handle can be cast to a GDALDataset *.
3890 : */
3891 :
3892 287 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3893 :
3894 : {
3895 287 : const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3896 287 : const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3897 : GDALDatasetH hDataset =
3898 287 : GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3899 287 : return hDataset;
3900 : }
3901 :
3902 : /************************************************************************/
3903 : /* GetSharedDS() */
3904 : /************************************************************************/
3905 :
3906 7515 : static GDALDataset *GetSharedDS(const char *pszFilename,
3907 : unsigned int nOpenFlags,
3908 : const char *const *papszOpenOptions)
3909 : {
3910 15030 : CPLMutexHolderD(&hDLMutex);
3911 :
3912 7515 : if (phSharedDatasetSet != nullptr)
3913 : {
3914 7286 : const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3915 : SharedDatasetCtxt sStruct;
3916 :
3917 7286 : sStruct.nPID = nThisPID;
3918 7286 : sStruct.pszDescription = const_cast<char *>(pszFilename);
3919 7286 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3920 : std::string osConcatenatedOpenOptions =
3921 7286 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3922 7286 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3923 7286 : sStruct.poDS = nullptr;
3924 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3925 7286 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3926 7286 : if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3927 : {
3928 158 : sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3929 : psStruct = static_cast<SharedDatasetCtxt *>(
3930 158 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3931 : }
3932 7286 : if (psStruct)
3933 : {
3934 7129 : return psStruct->poDS;
3935 : }
3936 : }
3937 386 : return nullptr;
3938 : }
3939 :
3940 : /************************************************************************/
3941 : /* GDALOpenEx() */
3942 : /************************************************************************/
3943 :
3944 : /**
3945 : * \brief Open a raster or vector file as a GDALDataset.
3946 : *
3947 : * This function will try to open the passed file, or virtual dataset
3948 : * name by invoking the Open method of each registered GDALDriver in turn.
3949 : * The first successful open will result in a returned dataset. If all
3950 : * drivers fail then NULL is returned and an error is issued.
3951 : *
3952 : * Several recommendations :
3953 : * <ul>
3954 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3955 : * recommended to open a new dataset on the same underlying file.</li>
3956 : * <li>The returned dataset should only be accessed by one thread at a time. If
3957 : * you want to use it from different threads, you must add all necessary code
3958 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3959 : * as GeoTIFF, maintain internal state variables that are updated each time a
3960 : * new block is read, thus preventing concurrent use.) </li>
3961 : * </ul>
3962 : *
3963 : * For drivers supporting the VSI virtual file API, it is possible to open a
3964 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3965 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3966 : * server (see VSIInstallCurlFileHandler())
3967 : *
3968 : * In order to reduce the need for searches through the operating system
3969 : * file system machinery, it is possible to give an optional list of files with
3970 : * the papszSiblingFiles parameter.
3971 : * This is the list of all files at the same level in the file system as the
3972 : * target file, including the target file. The filenames must not include any
3973 : * path components, are essentially just the output of VSIReadDir() on the
3974 : * parent directory. If the target object does not have filesystem semantics
3975 : * then the file list should be NULL.
3976 : *
3977 : * @param pszFilename the name of the file to access. In the case of
3978 : * exotic drivers this may not refer to a physical file, but instead contain
3979 : * information for the driver on how to access a dataset. It should be in UTF-8
3980 : * encoding.
3981 : *
3982 : * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3983 : * through logical or operator.
3984 : * <ul>
3985 : * <li>Driver kind:
3986 : * <ul>
3987 : * <li>GDAL_OF_RASTER for raster drivers,</li>
3988 : * <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3989 : * <li>GDAL_OF_VECTOR for vector drivers,</li>
3990 : * <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3991 : * </ul>
3992 : * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3993 : * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3994 : * | GDAL_OF_GNM is implied.
3995 : * </li>
3996 : * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3997 : * </li>
3998 : * <li>Shared mode: GDAL_OF_SHARED. If set,
3999 : * it allows the sharing of GDALDataset handles for a dataset with other callers
4000 : * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
4001 : * its list of currently open and shared GDALDataset's, and if the
4002 : * GetDescription() name for one exactly matches the pszFilename passed to
4003 : * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
4004 : * from the same thread.
4005 : * </li>
4006 : * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
4007 : * This must be use in combination with GDAL_OF_RASTER, and is mutually
4008 : * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4009 : * GDAL_OF_GNM.
4010 : * </li>
4011 : * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4012 : * a failed attempt to open the file will lead to an error message to be
4013 : * reported.
4014 : * </li>
4015 : * </ul>
4016 : *
4017 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4018 : * terminated list of strings with the driver short names that must be
4019 : * considered.
4020 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4021 : * followed by the driver short name can be used to exclude a driver.
4022 : *
4023 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4024 : * options passed to candidate drivers. An option exists for all drivers,
4025 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4026 : * The level index starts at 0. The level number can be suffixed by "only" to
4027 : * specify that only this overview level must be visible, and not sub-levels.
4028 : * Open options are validated by default, and a warning is emitted in case the
4029 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4030 : * when not knowing which driver will open the file), so the special open option
4031 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4032 : * that it may not cause a warning if the driver doesn't declare this option.
4033 : * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4034 : * no overviews should be exposed.
4035 : *
4036 : * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4037 : * filenames that are auxiliary to the main filename. If NULL is passed, a
4038 : * probing of the file system will be done.
4039 : *
4040 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4041 : * this handle can be cast to a GDALDataset *.
4042 : *
4043 : */
4044 :
4045 88330 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4046 : unsigned int nOpenFlags,
4047 : const char *const *papszAllowedDrivers,
4048 : const char *const *papszOpenOptions,
4049 : const char *const *papszSiblingFiles)
4050 : {
4051 88330 : VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4052 :
4053 : // Do some sanity checks on incompatible flags with thread-safe mode.
4054 88330 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4055 : {
4056 : const struct
4057 : {
4058 : int nFlag;
4059 : const char *pszFlagName;
4060 128 : } asFlags[] = {
4061 : {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4062 : {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4063 : {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4064 : {GDAL_OF_GNM, "GDAL_OF_GNM"},
4065 : };
4066 :
4067 630 : for (const auto &asFlag : asFlags)
4068 : {
4069 506 : if ((nOpenFlags & asFlag.nFlag) != 0)
4070 : {
4071 4 : CPLError(CE_Failure, CPLE_IllegalArg,
4072 : "GDAL_OF_THREAD_SAFE and %s are mutually "
4073 : "exclusive",
4074 4 : asFlag.pszFlagName);
4075 4 : return nullptr;
4076 : }
4077 : }
4078 : }
4079 :
4080 : // If no driver kind is specified, assume all are to be probed.
4081 88326 : if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4082 33974 : nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4083 :
4084 : /* -------------------------------------------------------------------- */
4085 : /* In case of shared dataset, first scan the existing list to see */
4086 : /* if it could already contain the requested dataset. */
4087 : /* -------------------------------------------------------------------- */
4088 88326 : if (nOpenFlags & GDAL_OF_SHARED)
4089 : {
4090 7515 : if (nOpenFlags & GDAL_OF_INTERNAL)
4091 : {
4092 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4093 : "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4094 0 : return nullptr;
4095 : }
4096 :
4097 : auto poSharedDS =
4098 7515 : GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4099 7515 : if (poSharedDS)
4100 : {
4101 7129 : poSharedDS->Reference();
4102 7129 : return poSharedDS;
4103 : }
4104 : }
4105 :
4106 81197 : CPLErrorReset();
4107 81197 : VSIErrorReset();
4108 :
4109 : // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4110 : // shared dataset was asked before.
4111 81197 : GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4112 :
4113 162394 : return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4114 81197 : .release();
4115 : }
4116 :
4117 : /************************************************************************/
4118 : /* GDALDataset::Open() */
4119 : /************************************************************************/
4120 :
4121 : /**
4122 : * \brief Open a raster or vector file as a GDALDataset.
4123 : *
4124 : * This function will use the passed open info on each registered GDALDriver in
4125 : * turn.
4126 : * The first successful open will result in a returned dataset. If all
4127 : * drivers fail then NULL is returned and an error is issued.
4128 : *
4129 : * Several recommendations :
4130 : * <ul>
4131 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4132 : * recommended to open a new dataset on the same underlying file.</li>
4133 : * <li>The returned dataset should only be accessed by one thread at a time. If
4134 : * you want to use it from different threads, you must add all necessary code
4135 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
4136 : * as GeoTIFF, maintain internal state variables that are updated each time a
4137 : * new block is read, thus preventing concurrent use.) </li>
4138 : * </ul>
4139 : *
4140 : * For drivers supporting the VSI virtual file API, it is possible to open a
4141 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4142 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4143 : * server (see VSIInstallCurlFileHandler())
4144 : *
4145 : * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4146 : * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4147 : * If shared dataset is needed, use GDALOpenEx() or the other variant of
4148 : * GDALDataset::Open()
4149 : *
4150 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4151 : * terminated list of strings with the driver short names that must be
4152 : * considered.
4153 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4154 : * followed by the driver short name can be used to exclude a driver.
4155 : *
4156 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4157 : * options passed to candidate drivers. An option exists for all drivers,
4158 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4159 : * The level index starts at 0. The level number can be suffixed by "only" to
4160 : * specify that only this overview level must be visible, and not sub-levels.
4161 : * Open options are validated by default, and a warning is emitted in case the
4162 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4163 : * when not knowing which driver will open the file), so the special open option
4164 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4165 : * that it may not cause a warning if the driver doesn't declare this option.
4166 : * OVERVIEW_LEVEL=NONE is supported to indicate that
4167 : * no overviews should be exposed.
4168 : *
4169 : * @return A GDALDataset unique pointer or NULL on failure.
4170 : *
4171 : * @since 3.13
4172 : */
4173 :
4174 : std::unique_ptr<GDALDataset>
4175 83192 : GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4176 : const char *const *papszAllowedDrivers,
4177 : const char *const *papszOpenOptions)
4178 : {
4179 : // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4180 : // into VSIKERCHUNK_USE_CACHE config option
4181 83192 : std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4182 83192 : if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4183 : {
4184 13 : poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4185 26 : "VSIKERCHUNK_USE_CACHE", "YES", false);
4186 : }
4187 :
4188 83192 : GDALDriverManager *poDM = GetGDALDriverManager();
4189 :
4190 83192 : CPLAssert(nullptr != poDM);
4191 :
4192 83192 : GDALOpenInfo &oOpenInfo = *poOpenInfo;
4193 83192 : const char *pszFilename = poOpenInfo->pszFilename;
4194 83192 : const int nOpenFlags = poOpenInfo->nOpenFlags;
4195 83192 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4196 :
4197 83192 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4198 83192 : if (sAntiRecursion.nRecLevel == 100)
4199 : {
4200 0 : CPLError(CE_Failure, CPLE_AppDefined,
4201 : "GDALOpen() called with too many recursion levels");
4202 0 : return nullptr;
4203 : }
4204 :
4205 166384 : std::string osAllowedDrivers;
4206 179406 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4207 96214 : osAllowedDrivers += pszDriverName;
4208 : auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4209 249576 : std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4210 83192 : if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4211 : {
4212 0 : CPLError(CE_Failure, CPLE_AppDefined,
4213 : "GDALOpen() called on %s recursively", pszFilename);
4214 0 : return nullptr;
4215 : }
4216 :
4217 : // Remove leading @ if present.
4218 : char **papszOpenOptionsCleaned =
4219 83192 : CSLDuplicate(const_cast<char **>(papszOpenOptions));
4220 89257 : for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4221 : ++papszIter)
4222 : {
4223 6065 : char *pszOption = *papszIter;
4224 6065 : if (pszOption[0] == '@')
4225 231 : memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4226 : }
4227 :
4228 83192 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4229 83192 : oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4230 :
4231 : #ifdef OGRAPISPY_ENABLED
4232 83192 : const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4233 : const int iSnapshot =
4234 45560 : (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4235 128752 : ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4236 83192 : : INT_MIN;
4237 : #endif
4238 :
4239 83192 : const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4240 83192 : GDALDriver *poMissingPluginDriver = nullptr;
4241 166384 : std::vector<GDALDriver *> apoSecondPassDrivers;
4242 :
4243 : // Lookup of matching driver for dataset can involve up to 2 passes:
4244 : // - in the first pass, all drivers that are compabile of the request mode
4245 : // (raster/vector/etc.) are probed using their Identify() method if it
4246 : // exists. If the Identify() method returns FALSE, the driver is skipped.
4247 : // If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4248 : // driver is a deferred-loading plugin, it is added to the
4249 : // apoSecondPassDrivers list for potential later probing, and execution
4250 : // continues to the next driver in the list.
4251 : // Otherwise if Identify() returns non-FALSE, the Open() method is used.
4252 : // If Open() returns a non-NULL dataset, the loop stops and it is
4253 : // returned. Otherwise looping over remaining drivers continues.
4254 : // - the second pass is optional, only if at least one driver was added
4255 : // into apoSecondPassDrivers during the first pass. It is similar
4256 : // to the first pass except it runs only on apoSecondPassDrivers drivers.
4257 : // And the Open() method of such drivers is used, causing them to be
4258 : // loaded for real.
4259 83192 : int iPass = 1;
4260 83206 : retry:
4261 8865030 : for (int iDriver = 0;
4262 8865060 : iDriver < (iPass == 1 ? nDriverCount
4263 36 : : static_cast<int>(apoSecondPassDrivers.size()));
4264 : ++iDriver)
4265 : {
4266 : GDALDriver *poDriver =
4267 8845940 : iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4268 27 : : apoSecondPassDrivers[iDriver];
4269 8845910 : const char *pszDriverName = GDALGetDriverShortName(poDriver);
4270 8845910 : if (pszDriverName && papszAllowedDrivers)
4271 : {
4272 3852020 : bool bDriverMatchedPositively = false;
4273 3852020 : bool bDriverMatchedNegatively = false;
4274 3852020 : bool bOnlyExcludedDrivers = true;
4275 18690200 : for (const char *pszAllowedDriver :
4276 41232400 : cpl::Iterate(papszAllowedDrivers))
4277 : {
4278 18690200 : if (pszAllowedDriver[0] != '-')
4279 18688700 : bOnlyExcludedDrivers = false;
4280 18690200 : if (EQUAL(pszAllowedDriver, pszDriverName))
4281 : {
4282 90961 : bDriverMatchedPositively = true;
4283 : }
4284 18599200 : else if (pszAllowedDriver[0] == '-' &&
4285 1486 : EQUAL(pszAllowedDriver + 1, pszDriverName))
4286 : {
4287 7 : bDriverMatchedNegatively = true;
4288 7 : break;
4289 : }
4290 : }
4291 3852020 : if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4292 : bDriverMatchedNegatively)
4293 : {
4294 8262100 : continue;
4295 : }
4296 : }
4297 :
4298 5088160 : if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4299 47251 : continue;
4300 :
4301 12884500 : if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4302 5447130 : (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4303 406217 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4304 85990 : continue;
4305 15676500 : if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4306 6928650 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4307 1973730 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4308 1482490 : continue;
4309 7632160 : if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4310 3821950 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4311 349522 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4312 326703 : continue;
4313 :
4314 : // Remove general OVERVIEW_LEVEL open options from list before passing
4315 : // it to the driver, if it isn't a driver specific option already.
4316 3145730 : char **papszTmpOpenOptions = nullptr;
4317 3145730 : char **papszTmpOpenOptionsToValidate = nullptr;
4318 3145730 : char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4319 3145730 : if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4320 3145880 : nullptr &&
4321 152 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4322 : {
4323 152 : papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4324 : papszTmpOpenOptions =
4325 152 : CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4326 152 : oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4327 :
4328 152 : papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4329 152 : papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4330 : "OVERVIEW_LEVEL", nullptr);
4331 152 : papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4332 : }
4333 :
4334 : const int nIdentifyRes =
4335 3145730 : poDriver->pfnIdentifyEx
4336 6291450 : ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4337 3145720 : : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4338 3145730 : : GDAL_IDENTIFY_UNKNOWN;
4339 3145730 : if (nIdentifyRes == FALSE)
4340 : {
4341 2561750 : CSLDestroy(papszTmpOpenOptions);
4342 2561750 : CSLDestroy(papszTmpOpenOptionsToValidate);
4343 2561750 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4344 2561750 : continue;
4345 : }
4346 583947 : else if (iPass == 1 && nIdentifyRes < 0 &&
4347 1168080 : poDriver->pfnOpen == nullptr &&
4348 161 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4349 : {
4350 : // Not loaded plugin
4351 156 : apoSecondPassDrivers.push_back(poDriver);
4352 156 : CSLDestroy(papszTmpOpenOptions);
4353 156 : CSLDestroy(papszTmpOpenOptionsToValidate);
4354 156 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4355 156 : continue;
4356 : }
4357 :
4358 583818 : const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4359 583818 : if (bIdentifyRes)
4360 : {
4361 63131 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4362 : }
4363 :
4364 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4365 : const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4366 : CPLErrorReset();
4367 : #endif
4368 :
4369 583818 : sAntiRecursion.nRecLevel++;
4370 583818 : sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4371 :
4372 583818 : GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4373 :
4374 583818 : sAntiRecursion.nRecLevel--;
4375 583818 : sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4376 :
4377 583818 : if (poDriver->pfnOpen != nullptr)
4378 : {
4379 : // If we couldn't determine for sure with Identify() (it returned
4380 : // -1), but Open() managed to open the file, post validate options.
4381 583815 : if (poDS != nullptr &&
4382 62783 : (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4383 62268 : !bIdentifyRes)
4384 : {
4385 889 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4386 : }
4387 : }
4388 3 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
4389 : {
4390 : // do nothing
4391 : }
4392 0 : else if (bIdentifyRes &&
4393 0 : poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4394 : {
4395 0 : if (!poMissingPluginDriver)
4396 : {
4397 0 : poMissingPluginDriver = poDriver;
4398 : }
4399 : }
4400 : else
4401 : {
4402 : // should not happen given the GDAL_DCAP_OPEN check
4403 0 : CSLDestroy(papszTmpOpenOptions);
4404 0 : CSLDestroy(papszTmpOpenOptionsToValidate);
4405 0 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4406 0 : continue;
4407 : }
4408 :
4409 583818 : CSLDestroy(papszTmpOpenOptions);
4410 583818 : CSLDestroy(papszTmpOpenOptionsToValidate);
4411 583818 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4412 :
4413 583818 : if (poDS != nullptr)
4414 : {
4415 62786 : if (poDS->papszOpenOptions == nullptr)
4416 : {
4417 62391 : poDS->papszOpenOptions = papszOpenOptionsCleaned;
4418 62391 : papszOpenOptionsCleaned = nullptr;
4419 : }
4420 :
4421 : // Deal with generic OVERVIEW_LEVEL open option, unless it is
4422 : // driver specific.
4423 62786 : if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4424 62825 : nullptr &&
4425 39 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4426 : {
4427 : CPLString osVal(
4428 78 : CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4429 39 : const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4430 : const bool bThisLevelOnly =
4431 39 : nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4432 : GDALDataset *poOvrDS =
4433 39 : GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4434 39 : if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4435 : {
4436 4 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4437 : {
4438 0 : CPLError(
4439 : CE_Warning, CPLE_NotSupported,
4440 : "A dataset opened by GDALOpenShared should have "
4441 : "the same filename (%s) "
4442 : "and description (%s)",
4443 0 : pszFilename, poDS->GetDescription());
4444 : }
4445 : else
4446 : {
4447 4 : CSLDestroy(poDS->papszOpenOptions);
4448 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4449 4 : poDS->papszOpenOptions = CSLSetNameValue(
4450 : poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4451 : }
4452 : }
4453 39 : poDS->ReleaseRef();
4454 39 : poDS = poOvrDS;
4455 39 : if (poDS == nullptr)
4456 : {
4457 1 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4458 : {
4459 1 : CPLError(CE_Failure, CPLE_OpenFailed,
4460 : "Cannot open overview level %d of %s",
4461 : nOvrLevel, pszFilename);
4462 : }
4463 : }
4464 : else
4465 : {
4466 : // For thread-safe opening, currently poDS is what will be
4467 : // the "master" dataset owned by the thread-safe dataset
4468 : // returned to the user, hence we do not register it as a
4469 : // visible one in the open dataset list, or mark it as shared.
4470 38 : if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4471 36 : !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4472 : {
4473 35 : poDS->AddToDatasetOpenList();
4474 : }
4475 38 : if (nOpenFlags & GDAL_OF_SHARED)
4476 : {
4477 4 : CSLDestroy(poDS->papszOpenOptions);
4478 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4479 4 : poDS->nOpenFlags = nOpenFlags;
4480 4 : if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4481 4 : poDS->MarkAsShared();
4482 : }
4483 : }
4484 : }
4485 62747 : else if (nOpenFlags & GDAL_OF_SHARED)
4486 : {
4487 375 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4488 : {
4489 2 : CPLError(CE_Warning, CPLE_NotSupported,
4490 : "A dataset opened by GDALOpenShared should have "
4491 : "the same filename (%s) "
4492 : "and description (%s)",
4493 2 : pszFilename, poDS->GetDescription());
4494 : }
4495 373 : else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4496 : {
4497 : // For thread-safe opening, currently poDS is what will be
4498 : // the "master" dataset owned by the thread-safe dataset
4499 : // returned to the user, hence we do not or mark it as shared.
4500 373 : poDS->MarkAsShared();
4501 : }
4502 : }
4503 :
4504 62786 : VSIErrorReset();
4505 :
4506 62786 : CSLDestroy(papszOpenOptionsCleaned);
4507 :
4508 : #ifdef OGRAPISPY_ENABLED
4509 62786 : if (iSnapshot != INT_MIN)
4510 : {
4511 11955 : GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4512 11955 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4513 11955 : poDS = GDALDataset::FromHandle(hDS);
4514 : }
4515 : #endif
4516 :
4517 62786 : if (poDS)
4518 : {
4519 62785 : poDS->m_bCanBeReopened = true;
4520 :
4521 62785 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4522 : {
4523 : poDS =
4524 248 : GDALGetThreadSafeDataset(
4525 248 : std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4526 124 : .release();
4527 124 : if (poDS)
4528 : {
4529 124 : poDS->m_bCanBeReopened = true;
4530 124 : poDS->poDriver = poDriver;
4531 124 : poDS->nOpenFlags = nOpenFlags;
4532 124 : if (!(nOpenFlags & GDAL_OF_INTERNAL))
4533 124 : poDS->AddToDatasetOpenList();
4534 124 : if (nOpenFlags & GDAL_OF_SHARED)
4535 0 : poDS->MarkAsShared();
4536 : }
4537 : }
4538 : }
4539 :
4540 64091 : return std::unique_ptr<GDALDataset>(poDS);
4541 : }
4542 :
4543 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4544 : if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4545 : {
4546 : // In case the file descriptor was "consumed" by a driver
4547 : // that ultimately failed, re-open it for next drivers.
4548 : oOpenInfo.fpL = VSIFOpenL(
4549 : pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4550 : }
4551 : #else
4552 521032 : if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4553 : {
4554 1305 : CSLDestroy(papszOpenOptionsCleaned);
4555 :
4556 : #ifdef OGRAPISPY_ENABLED
4557 1305 : if (iSnapshot != INT_MIN)
4558 : {
4559 349 : GDALDatasetH hDS = nullptr;
4560 349 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4561 : }
4562 : #endif
4563 1305 : return nullptr;
4564 : }
4565 : #endif
4566 : }
4567 :
4568 : // cppcheck-suppress knownConditionTrueFalse
4569 19115 : if (iPass == 1 && !apoSecondPassDrivers.empty())
4570 : {
4571 14 : CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4572 14 : iPass = 2;
4573 14 : goto retry;
4574 : }
4575 :
4576 19101 : CSLDestroy(papszOpenOptionsCleaned);
4577 :
4578 : #ifdef OGRAPISPY_ENABLED
4579 19101 : if (iSnapshot != INT_MIN)
4580 : {
4581 697 : GDALDatasetH hDS = nullptr;
4582 697 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4583 : }
4584 : #endif
4585 :
4586 19101 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4587 : {
4588 12256 : std::string osHint;
4589 12256 : const CPLStringList aosVSIFSPrefixes(VSIFileManager::GetPrefixes());
4590 195901 : for (const char *pszFSPrefix : aosVSIFSPrefixes)
4591 : {
4592 189787 : auto poFS = VSIFileManager::GetHandler(pszFSPrefix);
4593 189787 : if (poFS)
4594 : {
4595 189787 : osHint = poFS->GetHintForPotentiallyRecognizedPath(pszFilename);
4596 189787 : if (!osHint.empty())
4597 : {
4598 28 : osHint = " Changing the filename to " + osHint +
4599 14 : " may help it to be recognized.";
4600 14 : break;
4601 : }
4602 : }
4603 : }
4604 :
4605 6128 : if (nDriverCount == 0)
4606 : {
4607 0 : CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4608 : }
4609 6128 : else if (poMissingPluginDriver)
4610 : {
4611 0 : std::string osMsg("`");
4612 0 : osMsg += pszFilename;
4613 : osMsg += "' not recognized as being in a supported file format. "
4614 0 : "It could have been recognized by driver ";
4615 0 : osMsg += poMissingPluginDriver->GetDescription();
4616 0 : osMsg += ", but plugin ";
4617 : osMsg +=
4618 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4619 :
4620 0 : CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4621 : }
4622 : // Check to see if there was a filesystem error, and report it if so.
4623 : // If not, return a more generic error.
4624 6128 : else if (!osHint.empty() && VSIGetLastErrorNo() == VSIE_FileError)
4625 : {
4626 5 : CPLError(CE_Failure, CPLE_FileIO, "%s.%s", VSIGetLastErrorMsg(),
4627 : osHint.c_str());
4628 : }
4629 6123 : else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4630 : {
4631 555 : if (oOpenInfo.bStatOK)
4632 : {
4633 548 : CPLError(CE_Failure, CPLE_OpenFailed,
4634 : "`%s' not recognized as being in a supported file "
4635 : "format.%s",
4636 : pszFilename, osHint.c_str());
4637 : }
4638 : else
4639 : {
4640 : // If Stat failed and no VSI error was set, assume it is because
4641 : // the file did not exist on the filesystem.
4642 7 : CPLError(CE_Failure, CPLE_OpenFailed,
4643 : "`%s' does not exist in the file system, "
4644 : "and is not recognized as a supported dataset name.%s",
4645 : pszFilename, osHint.c_str());
4646 : }
4647 : }
4648 : }
4649 :
4650 19101 : return nullptr;
4651 : }
4652 :
4653 : /************************************************************************/
4654 : /* GDALOpenShared() */
4655 : /************************************************************************/
4656 :
4657 : /**
4658 : * \brief Open a raster file as a GDALDataset.
4659 : *
4660 : * This function works the same as GDALOpen(), but allows the sharing of
4661 : * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4662 : *
4663 : * In particular, GDALOpenShared() will first consult its list of currently
4664 : * open and shared GDALDataset's, and if the GetDescription() name for one
4665 : * exactly matches the pszFilename passed to GDALOpenShared() it will be
4666 : * referenced and returned.
4667 : *
4668 : * If GDALOpenShared() is called on the same
4669 : * pszFilename from two different threads, a different GDALDataset object will
4670 : * be returned as it is not safe to use the same dataset from different threads,
4671 : * unless the user does explicitly use mutexes in its code.
4672 : *
4673 : * For drivers supporting the VSI virtual file API, it is possible to open a
4674 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4675 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4676 : * server (see VSIInstallCurlFileHandler())
4677 : *
4678 : * \sa GDALOpen()
4679 : * \sa GDALOpenEx()
4680 : *
4681 : * @param pszFilename the name of the file to access. In the case of
4682 : * exotic drivers this may not refer to a physical file, but instead contain
4683 : * information for the driver on how to access a dataset. It should be in
4684 : * UTF-8 encoding.
4685 : *
4686 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
4687 : * drivers support only read only access.
4688 : *
4689 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4690 : * this handle can be cast to a GDALDataset *.
4691 : */
4692 :
4693 5209 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4694 : GDALAccess eAccess)
4695 : {
4696 5209 : VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4697 5209 : return GDALOpenEx(pszFilename,
4698 : GDAL_OF_RASTER |
4699 : (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4700 : GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4701 5209 : nullptr, nullptr, nullptr);
4702 : }
4703 :
4704 : /************************************************************************/
4705 : /* GDALClose() */
4706 : /************************************************************************/
4707 :
4708 : /**
4709 : * \brief Close GDAL dataset.
4710 : *
4711 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4712 : * using the C++ "delete" operator, recovering all dataset related resources.
4713 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4714 : * dereferenced, and closed only if the referenced count has dropped below 1.
4715 : *
4716 : * @param hDS The dataset to close, or nullptr.
4717 : * @return CE_None in case of success (return value since GDAL 3.7). On a
4718 : * shared dataset whose reference count is not dropped below 1, CE_None will
4719 : * be returned.
4720 : *
4721 : * @see GDALCloseEx()
4722 : */
4723 :
4724 87931 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4725 :
4726 : {
4727 87931 : return GDALCloseEx(hDS, nullptr, nullptr);
4728 : }
4729 :
4730 : /************************************************************************/
4731 : /* GDALCloseEx() */
4732 : /************************************************************************/
4733 :
4734 : /**
4735 : * \brief Close GDAL dataset.
4736 : *
4737 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4738 : * using the C++ "delete" operator, recovering all dataset related resources.
4739 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4740 : * dereferenced, and closed only if the referenced count has dropped below 1.
4741 : *
4742 : * This function may report progress if a progress
4743 : * callback if provided in the pfnProgress argument and if the dataset returns
4744 : * true for GDALDataset::GetCloseReportsProgress()
4745 :
4746 : * @param hDS The dataset to close, or nullptr
4747 : * @param pfnProgress Progress callback, or nullptr
4748 : * @param pProgressData User data of progress callback, or nullptr
4749 : *
4750 : * @return CE_None in case of success. On a
4751 : * shared dataset whose reference count is not dropped below 1, CE_None will
4752 : * be returned.
4753 : *
4754 : * @since GDAL 3.13
4755 : * @see GDALClose()
4756 : */
4757 :
4758 92468 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4759 : void *pProgressData)
4760 : {
4761 92468 : if (!hDS)
4762 405 : return CE_None;
4763 :
4764 : #ifdef OGRAPISPY_ENABLED
4765 92063 : if (bOGRAPISpyEnabled)
4766 11 : OGRAPISpyPreClose(hDS);
4767 : #endif
4768 :
4769 92063 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4770 :
4771 92063 : if (poDS->GetShared())
4772 : {
4773 : /* --------------------------------------------------------------------
4774 : */
4775 : /* If this file is in the shared dataset list then dereference */
4776 : /* it, and only delete/remote it if the reference count has */
4777 : /* dropped to zero. */
4778 : /* --------------------------------------------------------------------
4779 : */
4780 233 : if (poDS->Dereference() > 0)
4781 14 : return CE_None;
4782 : }
4783 :
4784 92049 : CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4785 92049 : delete poDS;
4786 :
4787 : #ifdef OGRAPISPY_ENABLED
4788 92049 : if (bOGRAPISpyEnabled)
4789 11 : OGRAPISpyPostClose();
4790 : #endif
4791 92049 : return eErr;
4792 : }
4793 :
4794 : /************************************************************************/
4795 : /* GDALDumpOpenDataset() */
4796 : /************************************************************************/
4797 :
4798 0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4799 : {
4800 0 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4801 0 : FILE *fp = static_cast<FILE *>(user_data);
4802 0 : GDALDataset *poDS = psStruct->poDS;
4803 :
4804 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4805 0 : ? "DriverIsNULL"
4806 0 : : poDS->GetDriver()->GetDescription();
4807 :
4808 0 : poDS->Reference();
4809 0 : CPL_IGNORE_RET_VAL(
4810 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4811 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName,
4812 0 : static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4813 : poDS->GetRasterYSize(), poDS->GetRasterCount(),
4814 0 : poDS->GetDescription()));
4815 :
4816 0 : return TRUE;
4817 : }
4818 :
4819 0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4820 : {
4821 :
4822 : // Don't list shared datasets. They have already been listed by
4823 : // GDALDumpOpenSharedDatasetsForeach.
4824 0 : if (poDS->GetShared())
4825 0 : return TRUE;
4826 :
4827 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4828 0 : ? "DriverIsNULL"
4829 0 : : poDS->GetDriver()->GetDescription();
4830 :
4831 0 : poDS->Reference();
4832 0 : CPL_IGNORE_RET_VAL(
4833 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4834 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4835 : poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4836 0 : poDS->GetRasterCount(), poDS->GetDescription()));
4837 :
4838 0 : return TRUE;
4839 : }
4840 :
4841 : /**
4842 : * \brief List open datasets.
4843 : *
4844 : * Dumps a list of all open datasets (shared or not) to the indicated
4845 : * text file (may be stdout or stderr). This function is primarily intended
4846 : * to assist in debugging "dataset leaks" and reference counting issues.
4847 : * The information reported includes the dataset name, referenced count,
4848 : * shared status, driver name, size, and band count.
4849 : */
4850 :
4851 272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4852 :
4853 : {
4854 272 : VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4855 :
4856 544 : CPLMutexHolderD(&hDLMutex);
4857 :
4858 272 : if (poAllDatasetMap == nullptr)
4859 272 : return 0;
4860 :
4861 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4862 :
4863 0 : for (const auto &oIter : *poAllDatasetMap)
4864 : {
4865 0 : GDALDumpOpenDatasetsForeach(oIter.first, fp);
4866 : }
4867 :
4868 0 : if (phSharedDatasetSet != nullptr)
4869 : {
4870 0 : CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4871 : fp);
4872 : }
4873 0 : return static_cast<int>(poAllDatasetMap->size());
4874 : }
4875 :
4876 : /************************************************************************/
4877 : /* BeginAsyncReader() */
4878 : /************************************************************************/
4879 :
4880 : /**
4881 : * \brief Sets up an asynchronous data request
4882 : *
4883 : * This method establish an asynchronous raster read request for the
4884 : * indicated window on the dataset into the indicated buffer. The parameters
4885 : * for windowing, buffer size, buffer type and buffer organization are similar
4886 : * to those for GDALDataset::RasterIO(); however, this call only launches
4887 : * the request and filling the buffer is accomplished via calls to
4888 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4889 : *
4890 : * Once all processing for the created session is complete, or if no further
4891 : * refinement of the request is required, the GDALAsyncReader object should
4892 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4893 : *
4894 : * Note that the data buffer (pData) will potentially continue to be
4895 : * updated as long as the session lives, but it is not deallocated when
4896 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4897 : * should be deallocated by the application at that point.
4898 : *
4899 : * Additional information on asynchronous IO in GDAL may be found at:
4900 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4901 : *
4902 : * This method is the same as the C GDALBeginAsyncReader() function.
4903 : *
4904 : * @param nXOff The pixel offset to the top left corner of the region
4905 : * of the band to be accessed. This would be zero to start from the left side.
4906 : *
4907 : * @param nYOff The line offset to the top left corner of the region
4908 : * of the band to be accessed. This would be zero to start from the top.
4909 : *
4910 : * @param nXSize The width of the region of the band to be accessed in pixels.
4911 : *
4912 : * @param nYSize The height of the region of the band to be accessed in lines.
4913 : *
4914 : * @param pBuf The buffer into which the data should be read. This buffer must
4915 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4916 : * It is organized in left to right,top to bottom pixel order. Spacing is
4917 : * controlled by the nPixelSpace, and nLineSpace parameters.
4918 : *
4919 : * @param nBufXSize the width of the buffer image into which the desired region
4920 : * is to be read, or from which it is to be written.
4921 : *
4922 : * @param nBufYSize the height of the buffer image into which the desired
4923 : * region is to be read, or from which it is to be written.
4924 : *
4925 : * @param eBufType the type of the pixel values in the pData data buffer. The
4926 : * pixel values will automatically be translated to/from the GDALRasterBand
4927 : * data type as needed.
4928 : *
4929 : * @param nBandCount the number of bands being read or written.
4930 : *
4931 : * @param panBandMap the list of nBandCount band numbers being read/written.
4932 : * Note band numbers are 1 based. This may be NULL to select the first
4933 : * nBandCount bands.
4934 : *
4935 : * @param nPixelSpace The byte offset from the start of one pixel value in
4936 : * pData to the start of the next pixel value within a scanline. If defaulted
4937 : * (0) the size of the datatype eBufType is used.
4938 : *
4939 : * @param nLineSpace The byte offset from the start of one scanline in
4940 : * pData to the start of the next. If defaulted the size of the datatype
4941 : * eBufType * nBufXSize is used.
4942 : *
4943 : * @param nBandSpace the byte offset from the start of one bands data to the
4944 : * start of the next. If defaulted (zero) the value will be
4945 : * nLineSpace * nBufYSize implying band sequential organization
4946 : * of the data buffer.
4947 : *
4948 : * @param papszOptions Driver specific control options in a string list or NULL.
4949 : * Consult driver documentation for options supported.
4950 : *
4951 : * @return The GDALAsyncReader object representing the request.
4952 : */
4953 :
4954 1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
4955 : int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4956 : int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4957 : int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4958 : {
4959 : // See gdaldefaultasync.cpp
4960 :
4961 1 : return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4962 : nBufXSize, nBufYSize, eBufType, nBandCount,
4963 : panBandMap, nPixelSpace, nLineSpace,
4964 1 : nBandSpace, papszOptions);
4965 : }
4966 :
4967 : /************************************************************************/
4968 : /* GDALBeginAsyncReader() */
4969 : /************************************************************************/
4970 :
4971 : /**
4972 : * \brief Sets up an asynchronous data request
4973 : *
4974 : * This method establish an asynchronous raster read request for the
4975 : * indicated window on the dataset into the indicated buffer. The parameters
4976 : * for windowing, buffer size, buffer type and buffer organization are similar
4977 : * to those for GDALDataset::RasterIO(); however, this call only launches
4978 : * the request and filling the buffer is accomplished via calls to
4979 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4980 : *
4981 : * Once all processing for the created session is complete, or if no further
4982 : * refinement of the request is required, the GDALAsyncReader object should
4983 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4984 : *
4985 : * Note that the data buffer (pData) will potentially continue to be
4986 : * updated as long as the session lives, but it is not deallocated when
4987 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4988 : * should be deallocated by the application at that point.
4989 : *
4990 : * Additional information on asynchronous IO in GDAL may be found at:
4991 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4992 : *
4993 : * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4994 : *
4995 : * @param hDS handle to the dataset object.
4996 : *
4997 : * @param nXOff The pixel offset to the top left corner of the region
4998 : * of the band to be accessed. This would be zero to start from the left side.
4999 : *
5000 : * @param nYOff The line offset to the top left corner of the region
5001 : * of the band to be accessed. This would be zero to start from the top.
5002 : *
5003 : * @param nXSize The width of the region of the band to be accessed in pixels.
5004 : *
5005 : * @param nYSize The height of the region of the band to be accessed in lines.
5006 : *
5007 : * @param pBuf The buffer into which the data should be read. This buffer must
5008 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
5009 : * It is organized in left to right,top to bottom pixel order. Spacing is
5010 : * controlled by the nPixelSpace, and nLineSpace parameters.
5011 : *
5012 : * @param nBufXSize the width of the buffer image into which the desired region
5013 : * is to be read, or from which it is to be written.
5014 : *
5015 : * @param nBufYSize the height of the buffer image into which the desired
5016 : * region is to be read, or from which it is to be written.
5017 : *
5018 : * @param eBufType the type of the pixel values in the pData data buffer. The
5019 : * pixel values will automatically be translated to/from the GDALRasterBand
5020 : * data type as needed.
5021 : *
5022 : * @param nBandCount the number of bands being read or written.
5023 : *
5024 : * @param panBandMap the list of nBandCount band numbers being read/written.
5025 : * Note band numbers are 1 based. This may be NULL to select the first
5026 : * nBandCount bands.
5027 : *
5028 : * @param nPixelSpace The byte offset from the start of one pixel value in
5029 : * pData to the start of the next pixel value within a scanline. If defaulted
5030 : * (0) the size of the datatype eBufType is used.
5031 : *
5032 : * @param nLineSpace The byte offset from the start of one scanline in
5033 : * pData to the start of the next. If defaulted the size of the datatype
5034 : * eBufType * nBufXSize is used.
5035 : *
5036 : * @param nBandSpace the byte offset from the start of one bands data to the
5037 : * start of the next. If defaulted (zero) the value will be
5038 : * nLineSpace * nBufYSize implying band sequential organization
5039 : * of the data buffer.
5040 : *
5041 : * @param papszOptions Driver specific control options in a string list or NULL.
5042 : * Consult driver documentation for options supported.
5043 : *
5044 : * @return handle representing the request.
5045 : */
5046 :
5047 2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5048 : GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5049 : int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5050 : int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5051 : CSLConstList papszOptions)
5052 :
5053 : {
5054 2 : VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5055 : return static_cast<GDALAsyncReaderH>(
5056 2 : GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5057 : nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5058 : nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5059 2 : const_cast<char **>(papszOptions)));
5060 : }
5061 :
5062 : /************************************************************************/
5063 : /* EndAsyncReader() */
5064 : /************************************************************************/
5065 :
5066 : /**
5067 : * End asynchronous request.
5068 : *
5069 : * This method destroys an asynchronous io request and recovers all
5070 : * resources associated with it.
5071 : *
5072 : * This method is the same as the C function GDALEndAsyncReader().
5073 : *
5074 : * @param poARIO pointer to a GDALAsyncReader
5075 : */
5076 :
5077 1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5078 : {
5079 1 : delete poARIO;
5080 1 : }
5081 :
5082 : /************************************************************************/
5083 : /* GDALEndAsyncReader() */
5084 : /************************************************************************/
5085 :
5086 : /**
5087 : * End asynchronous request.
5088 : *
5089 : * This method destroys an asynchronous io request and recovers all
5090 : * resources associated with it.
5091 : *
5092 : * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5093 : *
5094 : * @param hDS handle to the dataset object.
5095 : * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5096 : */
5097 :
5098 1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5099 : GDALAsyncReaderH hAsyncReaderH)
5100 : {
5101 1 : VALIDATE_POINTER0(hDS, "GDALDataset");
5102 1 : VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5103 1 : GDALDataset::FromHandle(hDS)->EndAsyncReader(
5104 1 : static_cast<GDALAsyncReader *>(hAsyncReaderH));
5105 : }
5106 :
5107 : /************************************************************************/
5108 : /* CloseDependentDatasets() */
5109 : /************************************************************************/
5110 :
5111 : /**
5112 : * Drop references to any other datasets referenced by this dataset.
5113 : *
5114 : * This method should release any reference to other datasets (e.g. a VRT
5115 : * dataset to its sources), but not close the current dataset itself.
5116 : *
5117 : * If at least, one reference to a dependent dataset has been dropped,
5118 : * this method should return TRUE. Otherwise it *should* return FALSE.
5119 : * (Failure to return the proper value might result in infinite loop)
5120 : *
5121 : * This method can be called several times on a given dataset. After
5122 : * the first time, it should not do anything and return FALSE.
5123 : *
5124 : * The driver implementation may choose to destroy its raster bands,
5125 : * so be careful not to call any method on the raster bands afterwards.
5126 : *
5127 : * Basically the only safe action you can do after calling
5128 : * CloseDependentDatasets() is to call the destructor.
5129 : *
5130 : * Note: the only legitimate caller of CloseDependentDatasets() is
5131 : * GDALDriverManager::~GDALDriverManager()
5132 : *
5133 : * @return TRUE if at least one reference to another dataset has been dropped.
5134 : */
5135 20011 : int GDALDataset::CloseDependentDatasets()
5136 : {
5137 20011 : return oOvManager.CloseDependentDatasets();
5138 : }
5139 :
5140 : /************************************************************************/
5141 : /* ReportError() */
5142 : /************************************************************************/
5143 :
5144 : #ifndef DOXYGEN_XML
5145 : /**
5146 : * \brief Emits an error related to a dataset.
5147 : *
5148 : * This function is a wrapper for regular CPLError(). The only difference
5149 : * with CPLError() is that it prepends the error message with the dataset
5150 : * name.
5151 : *
5152 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5153 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5154 : * @param fmt a printf() style format string. Any additional arguments
5155 : * will be treated as arguments to fill in this format in a manner
5156 : * similar to printf().
5157 : *
5158 : */
5159 :
5160 103 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5161 : const char *fmt, ...) const
5162 : {
5163 : va_list args;
5164 103 : va_start(args, fmt);
5165 103 : ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5166 103 : va_end(args);
5167 103 : }
5168 :
5169 : /**
5170 : * \brief Emits an error related to a dataset (static method)
5171 : *
5172 : * This function is a wrapper for regular CPLError(). The only difference
5173 : * with CPLError() is that it prepends the error message with the dataset
5174 : * name.
5175 : *
5176 : * @param pszDSName dataset name.
5177 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5178 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5179 : * @param fmt a printf() style format string. Any additional arguments
5180 : * will be treated as arguments to fill in this format in a manner
5181 : * similar to printf().
5182 : *
5183 : * @since GDAL 3.2.0
5184 : */
5185 :
5186 187 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5187 : CPLErrorNum err_no, const char *fmt, ...)
5188 : {
5189 : va_list args;
5190 187 : va_start(args, fmt);
5191 187 : ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5192 187 : va_end(args);
5193 187 : }
5194 :
5195 290 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5196 : CPLErrorNum err_no, const char *fmt,
5197 : va_list args)
5198 : {
5199 290 : pszDSName = CPLGetFilename(pszDSName);
5200 290 : if (pszDSName[0] != '\0')
5201 : {
5202 272 : CPLError(eErrClass, err_no, "%s",
5203 544 : std::string(pszDSName)
5204 272 : .append(": ")
5205 544 : .append(CPLString().vPrintf(fmt, args))
5206 : .c_str());
5207 : }
5208 : else
5209 : {
5210 18 : CPLErrorV(eErrClass, err_no, fmt, args);
5211 : }
5212 290 : }
5213 : #endif
5214 :
5215 : /************************************************************************/
5216 : /* GetMetadata() */
5217 : /************************************************************************/
5218 75455 : CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5219 : {
5220 : #ifndef WITHOUT_DERIVED
5221 75455 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5222 : {
5223 10 : oDerivedMetadataList.Clear();
5224 :
5225 : // First condition: at least one raster band.
5226 10 : if (GetRasterCount() > 0)
5227 : {
5228 : // Check if there is at least one complex band.
5229 10 : bool hasAComplexBand = false;
5230 :
5231 19 : for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5232 : {
5233 11 : if (GDALDataTypeIsComplex(
5234 11 : GetRasterBand(rasterId)->GetRasterDataType()))
5235 : {
5236 2 : hasAComplexBand = true;
5237 2 : break;
5238 : }
5239 : }
5240 :
5241 10 : unsigned int nbSupportedDerivedDS = 0;
5242 : const DerivedDatasetDescription *poDDSDesc =
5243 10 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5244 :
5245 10 : int nNumDataset = 1;
5246 80 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5247 : ++derivedId)
5248 : {
5249 126 : if (hasAComplexBand ||
5250 126 : CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5251 : "complex")
5252 : {
5253 : oDerivedMetadataList.SetNameValue(
5254 : CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5255 : CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5256 22 : poDDSDesc[derivedId].pszDatasetName,
5257 22 : GetDescription()));
5258 :
5259 : CPLString osDesc(
5260 : CPLSPrintf("%s from %s",
5261 22 : poDDSDesc[derivedId].pszDatasetDescription,
5262 22 : GetDescription()));
5263 : oDerivedMetadataList.SetNameValue(
5264 : CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5265 22 : osDesc.c_str());
5266 :
5267 22 : nNumDataset++;
5268 : }
5269 : }
5270 : }
5271 10 : return oDerivedMetadataList.List();
5272 : }
5273 : #endif
5274 :
5275 75445 : return GDALMajorObject::GetMetadata(pszDomain);
5276 : }
5277 :
5278 : // clang-format off
5279 :
5280 : /**
5281 : * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5282 : * \brief Set metadata.
5283 : *
5284 : * CAUTION: depending on the format, older values of the updated information
5285 : * might still be found in the file in a "ghost" state, even if no longer
5286 : * accessible through the GDAL API. This is for example the case of the GTiff
5287 : * format (this is not a exhaustive list)
5288 : *
5289 : * The C function GDALSetMetadata() does the same thing as this method.
5290 : *
5291 : * @param papszMetadata the metadata in name=value string list format to
5292 : * apply.
5293 : * @param pszDomain the domain of interest. Use "" or NULL for the default
5294 : * domain.
5295 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5296 : * metadata has been accepted, but is likely not maintained persistently
5297 : * by the underlying object between sessions.
5298 : */
5299 :
5300 : /**
5301 : * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5302 : * \brief Set single metadata item.
5303 : *
5304 : * CAUTION: depending on the format, older values of the updated information
5305 : * might still be found in the file in a "ghost" state, even if no longer
5306 : * accessible through the GDAL API. This is for example the case of the GTiff
5307 : * format (this is not a exhaustive list)
5308 : *
5309 : * The C function GDALSetMetadataItem() does the same thing as this method.
5310 : *
5311 : * @param pszName the key for the metadata item to fetch.
5312 : * @param pszValue the value to assign to the key.
5313 : * @param pszDomain the domain to set within, use NULL for the default domain.
5314 : *
5315 : * @return CE_None on success, or an error code on failure.
5316 : */
5317 :
5318 : // clang-format on
5319 :
5320 : /************************************************************************/
5321 : /* GetMetadataDomainList() */
5322 : /************************************************************************/
5323 :
5324 1172 : char **GDALDataset::GetMetadataDomainList()
5325 : {
5326 1172 : char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5327 :
5328 : // Ensure that we do not duplicate DERIVED domain.
5329 1319 : if (GetRasterCount() > 0 &&
5330 147 : CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5331 : {
5332 : currentDomainList =
5333 147 : CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5334 : }
5335 1172 : return currentDomainList;
5336 : }
5337 :
5338 : /************************************************************************/
5339 : /* GetDriverName() */
5340 : /************************************************************************/
5341 :
5342 : /** Return driver name.
5343 : * @return driver name.
5344 : */
5345 2687 : const char *GDALDataset::GetDriverName() const
5346 : {
5347 2687 : if (poDriver)
5348 2673 : return poDriver->GetDescription();
5349 14 : return "";
5350 : }
5351 :
5352 : /************************************************************************/
5353 : /* GDALDatasetReleaseResultSet() */
5354 : /************************************************************************/
5355 :
5356 : /**
5357 : \brief Release results of ExecuteSQL().
5358 :
5359 : This function should only be used to deallocate OGRLayers resulting from
5360 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
5361 : results set before destroying the GDALDataset may cause errors.
5362 :
5363 : This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5364 :
5365 :
5366 : @param hDS the dataset handle.
5367 : @param hLayer the result of a previous ExecuteSQL() call.
5368 :
5369 : */
5370 3561 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5371 :
5372 : {
5373 3561 : VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5374 :
5375 : #ifdef OGRAPISPY_ENABLED
5376 3561 : if (bOGRAPISpyEnabled)
5377 6 : OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5378 : #endif
5379 :
5380 7122 : GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5381 3561 : OGRLayer::FromHandle(hLayer));
5382 : }
5383 :
5384 : /************************************************************************/
5385 : /* GDALDatasetGetLayerCount() */
5386 : /************************************************************************/
5387 :
5388 : /**
5389 : \brief Get the number of layers in this dataset.
5390 :
5391 : This function is the same as the C++ method GDALDataset::GetLayerCount()
5392 :
5393 :
5394 : @param hDS the dataset handle.
5395 : @return layer count.
5396 : */
5397 :
5398 3490 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5399 :
5400 : {
5401 3490 : VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5402 :
5403 : #ifdef OGRAPISPY_ENABLED
5404 3490 : if (bOGRAPISpyEnabled)
5405 2 : OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5406 : #endif
5407 :
5408 3490 : return GDALDataset::FromHandle(hDS)->GetLayerCount();
5409 : }
5410 :
5411 : /************************************************************************/
5412 : /* GDALDatasetGetLayer() */
5413 : /************************************************************************/
5414 :
5415 : /**
5416 : \brief Fetch a layer by index.
5417 :
5418 : The returned layer remains owned by the
5419 : GDALDataset and should not be deleted by the application.
5420 :
5421 : This function is the same as the C++ method GDALDataset::GetLayer()
5422 :
5423 :
5424 : @param hDS the dataset handle.
5425 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5426 :
5427 : @return the layer, or NULL if iLayer is out of range or an error occurs.
5428 : */
5429 :
5430 11096 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5431 :
5432 : {
5433 11096 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5434 :
5435 : OGRLayerH hLayer =
5436 11096 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5437 :
5438 : #ifdef OGRAPISPY_ENABLED
5439 11096 : if (bOGRAPISpyEnabled)
5440 3 : OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5441 : #endif
5442 :
5443 11096 : return hLayer;
5444 : }
5445 :
5446 : /************************************************************************/
5447 : /* GDALDatasetGetLayerByName() */
5448 : /************************************************************************/
5449 :
5450 : /**
5451 : \brief Fetch a layer by name.
5452 :
5453 : The returned layer remains owned by the
5454 : GDALDataset and should not be deleted by the application.
5455 :
5456 : This function is the same as the C++ method GDALDataset::GetLayerByName()
5457 :
5458 :
5459 : @param hDS the dataset handle.
5460 : @param pszName the layer name of the layer to fetch.
5461 :
5462 : @return the layer, or NULL if Layer is not found or an error occurs.
5463 : */
5464 :
5465 3548 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5466 :
5467 : {
5468 3548 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5469 :
5470 3548 : OGRLayerH hLayer = OGRLayer::ToHandle(
5471 3548 : GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5472 :
5473 : #ifdef OGRAPISPY_ENABLED
5474 3548 : if (bOGRAPISpyEnabled)
5475 4 : OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5476 : #endif
5477 :
5478 3548 : return hLayer;
5479 : }
5480 :
5481 : /************************************************************************/
5482 : /* GDALDatasetIsLayerPrivate() */
5483 : /************************************************************************/
5484 :
5485 : /**
5486 : \brief Returns true if the layer at the specified index is deemed a private or
5487 : system table, or an internal detail only.
5488 :
5489 : This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5490 :
5491 : @since GDAL 3.4
5492 :
5493 : @param hDS the dataset handle.
5494 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5495 :
5496 : @return true if the layer is a private or system table.
5497 : */
5498 :
5499 91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5500 :
5501 : {
5502 91 : VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5503 :
5504 91 : const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5505 :
5506 91 : return res ? 1 : 0;
5507 : }
5508 :
5509 : /************************************************************************/
5510 : /* GetLayerIndex() */
5511 : /************************************************************************/
5512 :
5513 : /**
5514 : \brief Returns the index of the layer specified by name.
5515 :
5516 : @since GDAL 3.12
5517 :
5518 : @param pszName layer name (not NULL)
5519 :
5520 : @return an index >= 0, or -1 if not found.
5521 : */
5522 :
5523 0 : int GDALDataset::GetLayerIndex(const char *pszName) const
5524 : {
5525 0 : const int nLayerCount = GetLayerCount();
5526 0 : int iMatch = -1;
5527 0 : for (int i = 0; i < nLayerCount; ++i)
5528 : {
5529 0 : if (const auto poLayer = GetLayer(i))
5530 : {
5531 0 : const char *pszLayerName = poLayer->GetDescription();
5532 0 : if (strcmp(pszName, pszLayerName) == 0)
5533 : {
5534 0 : iMatch = i;
5535 0 : break;
5536 : }
5537 0 : else if (EQUAL(pszName, pszLayerName))
5538 : {
5539 0 : iMatch = i;
5540 : }
5541 : }
5542 : }
5543 0 : return iMatch;
5544 : }
5545 :
5546 : /************************************************************************/
5547 : /* GDALDatasetDeleteLayer() */
5548 : /************************************************************************/
5549 :
5550 : /**
5551 : \brief Delete the indicated layer from the datasource.
5552 :
5553 : If this function is supported
5554 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5555 :
5556 : This method is the same as the C++ method GDALDataset::DeleteLayer().
5557 :
5558 :
5559 : @param hDS the dataset handle.
5560 : @param iLayer the index of the layer to delete.
5561 :
5562 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5563 : layers is not supported for this datasource.
5564 :
5565 : */
5566 41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5567 :
5568 : {
5569 41 : VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5570 :
5571 : #ifdef OGRAPISPY_ENABLED
5572 41 : if (bOGRAPISpyEnabled)
5573 2 : OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5574 : #endif
5575 :
5576 41 : return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5577 : }
5578 :
5579 : /************************************************************************/
5580 : /* CreateLayer() */
5581 : /************************************************************************/
5582 :
5583 : /**
5584 : \brief This method attempts to create a new layer on the dataset with the
5585 : indicated name, coordinate system, geometry type.
5586 :
5587 : The papszOptions argument
5588 : can be used to control driver specific creation options. These options are
5589 : normally documented in the format specific documentation.
5590 : That function will try to validate the creation option list passed to the
5591 : driver with the GDALValidateCreationOptions() method. This check can be
5592 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5593 : to NO.
5594 :
5595 : Drivers should extend the ICreateLayer() method and not
5596 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5597 : delegating the actual work to ICreateLayer().
5598 :
5599 : This method is the same as the C function GDALDatasetCreateLayer() and the
5600 : deprecated OGR_DS_CreateLayer().
5601 :
5602 : Example:
5603 :
5604 : \code{.cpp}
5605 : #include "gdal.h"
5606 : #include "cpl_string.h"
5607 :
5608 : ...
5609 :
5610 : OGRLayer *poLayer;
5611 : char **papszOptions;
5612 :
5613 : if( !poDS->TestCapability( ODsCCreateLayer ) )
5614 : {
5615 : ...
5616 : }
5617 :
5618 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5619 : poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5620 : papszOptions );
5621 : CSLDestroy( papszOptions );
5622 :
5623 : if( poLayer == NULL )
5624 : {
5625 : ...
5626 : }
5627 : \endcode
5628 :
5629 : @param pszName the name for the new layer. This should ideally not
5630 : match any existing layer on the datasource.
5631 : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
5632 : no coordinate system is available.
5633 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5634 : are no constraints on the types geometry to be written.
5635 : @param papszOptions a StringList of name=value options. Options are driver
5636 : specific.
5637 :
5638 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5639 :
5640 : */
5641 :
5642 8510 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5643 : const OGRSpatialReference *poSpatialRef,
5644 : OGRwkbGeometryType eGType,
5645 : CSLConstList papszOptions)
5646 :
5647 : {
5648 8510 : if (eGType == wkbNone)
5649 : {
5650 538 : return CreateLayer(pszName, nullptr, papszOptions);
5651 : }
5652 : else
5653 : {
5654 15944 : OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5655 7972 : oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5656 7972 : return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5657 : }
5658 : }
5659 :
5660 : /**
5661 : \brief This method attempts to create a new layer on the dataset with the
5662 : indicated name and geometry field definition.
5663 :
5664 : When poGeomFieldDefn is not null, most drivers should honor
5665 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5666 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5667 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5668 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5669 : very few currently.
5670 :
5671 : Note that even if a geometry coordinate precision is set and a driver honors the
5672 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5673 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5674 : with the coordinate precision. That is they are assumed to be valid once their
5675 : coordinates are rounded to it. If it might not be the case, the user may set
5676 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5677 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5678 : the passed geometries.
5679 :
5680 : The papszOptions argument
5681 : can be used to control driver specific creation options. These options are
5682 : normally documented in the format specific documentation.
5683 : This function will try to validate the creation option list passed to the
5684 : driver with the GDALValidateCreationOptions() method. This check can be
5685 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5686 : to NO.
5687 :
5688 : Drivers should extend the ICreateLayer() method and not
5689 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5690 : delegating the actual work to ICreateLayer().
5691 :
5692 : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5693 :
5694 : @param pszName the name for the new layer. This should ideally not
5695 : match any existing layer on the datasource.
5696 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
5697 : or NULL if there is no geometry field.
5698 : @param papszOptions a StringList of name=value options. Options are driver
5699 : specific.
5700 :
5701 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5702 : @since 3.9
5703 :
5704 : */
5705 :
5706 10097 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5707 : const OGRGeomFieldDefn *poGeomFieldDefn,
5708 : CSLConstList papszOptions)
5709 :
5710 : {
5711 10097 : if (CPLTestBool(
5712 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5713 : {
5714 10097 : ValidateLayerCreationOptions(papszOptions);
5715 : }
5716 :
5717 : OGRLayer *poLayer;
5718 10097 : if (poGeomFieldDefn)
5719 : {
5720 9114 : OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5721 9216 : if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5722 102 : !TestCapability(ODsCCurveGeometries))
5723 : {
5724 23 : oGeomFieldDefn.SetType(
5725 : OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5726 : }
5727 :
5728 9114 : poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5729 : }
5730 : else
5731 : {
5732 983 : poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5733 : }
5734 : #ifdef DEBUG
5735 10176 : if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5736 79 : !poLayer->TestCapability(OLCCurveGeometries))
5737 : {
5738 0 : CPLError(CE_Warning, CPLE_AppDefined,
5739 : "Inconsistent driver: Layer geometry type is non-linear, but "
5740 : "TestCapability(OLCCurveGeometries) returns FALSE.");
5741 : }
5742 : #endif
5743 :
5744 10097 : return poLayer;
5745 : }
5746 :
5747 : //! @cond Doxygen_Suppress
5748 :
5749 : // Technical override to avoid ambiguous choice between the old and new
5750 : // new CreateLayer() signatures.
5751 39 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5752 : {
5753 78 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5754 78 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5755 : }
5756 :
5757 : // Technical override to avoid ambiguous choice between the old and new
5758 : // new CreateLayer() signatures.
5759 1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5760 : {
5761 2 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5762 2 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5763 : }
5764 :
5765 : //!@endcond
5766 :
5767 : /************************************************************************/
5768 : /* GDALDatasetCreateLayer() */
5769 : /************************************************************************/
5770 :
5771 : /**
5772 : \brief This function attempts to create a new layer on the dataset with the
5773 : indicated name, coordinate system, geometry type.
5774 :
5775 : The papszOptions argument can be used to control driver specific creation
5776 : options. These options are normally documented in the format specific
5777 : documentation.
5778 :
5779 : This method is the same as the C++ method GDALDataset::CreateLayer().
5780 :
5781 : Example:
5782 :
5783 : \code{.c}
5784 : #include "gdal.h"
5785 : #include "cpl_string.h"
5786 :
5787 : ...
5788 :
5789 : OGRLayerH hLayer;
5790 : char **papszOptions;
5791 :
5792 : if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5793 : {
5794 : ...
5795 : }
5796 :
5797 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5798 : hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5799 : papszOptions );
5800 : CSLDestroy( papszOptions );
5801 :
5802 : if( hLayer == NULL )
5803 : {
5804 : ...
5805 : }
5806 : \endcode
5807 :
5808 :
5809 : @param hDS the dataset handle
5810 : @param pszName the name for the new layer. This should ideally not
5811 : match any existing layer on the datasource.
5812 : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
5813 : no coordinate system is available.
5814 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5815 : are no constraints on the types geometry to be written.
5816 : @param papszOptions a StringList of name=value options. Options are driver
5817 : specific.
5818 :
5819 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5820 :
5821 : */
5822 :
5823 6623 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5824 : OGRSpatialReferenceH hSpatialRef,
5825 : OGRwkbGeometryType eGType,
5826 : CSLConstList papszOptions)
5827 :
5828 : {
5829 6623 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5830 :
5831 6623 : if (pszName == nullptr)
5832 : {
5833 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5834 : "Name was NULL in GDALDatasetCreateLayer");
5835 0 : return nullptr;
5836 : }
5837 :
5838 : OGRLayerH hLayer =
5839 13246 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5840 6623 : pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5841 : const_cast<char **>(papszOptions)));
5842 :
5843 : #ifdef OGRAPISPY_ENABLED
5844 6623 : if (bOGRAPISpyEnabled)
5845 8 : OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5846 : const_cast<char **>(papszOptions), hLayer);
5847 : #endif
5848 :
5849 6623 : return hLayer;
5850 : }
5851 :
5852 : /************************************************************************/
5853 : /* GDALDatasetCreateLayerFromGeomFieldDefn() */
5854 : /************************************************************************/
5855 :
5856 : /**
5857 : \brief This function attempts to create a new layer on the dataset with the
5858 : indicated name and geometry field.
5859 :
5860 : When poGeomFieldDefn is not null, most drivers should honor
5861 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5862 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5863 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5864 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5865 : very few currently.
5866 :
5867 : Note that even if a geometry coordinate precision is set and a driver honors the
5868 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5869 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5870 : with the coordinate precision. That is they are assumed to be valid once their
5871 : coordinates are rounded to it. If it might not be the case, the user may set
5872 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5873 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5874 : the passed geometries.
5875 :
5876 : The papszOptions argument can be used to control driver specific creation
5877 : options. These options are normally documented in the format specific
5878 : documentation.
5879 :
5880 : This method is the same as the C++ method GDALDataset::CreateLayer().
5881 :
5882 : @param hDS the dataset handle
5883 : @param pszName the name for the new layer. This should ideally not
5884 : match any existing layer on the datasource.
5885 : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5886 : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5887 : for drivers supporting that interface).
5888 : @param papszOptions a StringList of name=value options. Options are driver
5889 : specific.
5890 :
5891 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5892 :
5893 : @since GDAL 3.9
5894 :
5895 : */
5896 :
5897 : OGRLayerH
5898 14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5899 : OGRGeomFieldDefnH hGeomFieldDefn,
5900 : CSLConstList papszOptions)
5901 :
5902 : {
5903 14 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5904 :
5905 14 : if (!pszName)
5906 : {
5907 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5908 : "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5909 0 : return nullptr;
5910 : }
5911 :
5912 : OGRLayerH hLayer =
5913 28 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5914 14 : pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5915 : papszOptions));
5916 14 : return hLayer;
5917 : }
5918 :
5919 : /************************************************************************/
5920 : /* GDALDatasetCopyLayer() */
5921 : /************************************************************************/
5922 :
5923 : /**
5924 : \brief Duplicate an existing layer.
5925 :
5926 : This function creates a new layer, duplicate the field definitions of the
5927 : source layer and then duplicate each features of the source layer.
5928 : The papszOptions argument
5929 : can be used to control driver specific creation options. These options are
5930 : normally documented in the format specific documentation.
5931 : The source layer may come from another dataset.
5932 :
5933 : This method is the same as the C++ method GDALDataset::CopyLayer()
5934 :
5935 :
5936 : @param hDS the dataset handle.
5937 : @param hSrcLayer source layer.
5938 : @param pszNewName the name of the layer to create.
5939 : @param papszOptions a StringList of name=value options. Options are driver
5940 : specific.
5941 :
5942 : @return a handle to the layer, or NULL if an error occurs.
5943 : */
5944 52 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5945 : const char *pszNewName,
5946 : CSLConstList papszOptions)
5947 :
5948 : {
5949 52 : VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5950 52 : VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5951 52 : VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5952 :
5953 104 : return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5954 104 : OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5955 : }
5956 :
5957 : /************************************************************************/
5958 : /* GDALDatasetExecuteSQL() */
5959 : /************************************************************************/
5960 :
5961 : /**
5962 : \brief Execute an SQL statement against the data store.
5963 :
5964 : The result of an SQL query is either NULL for statements that are in error,
5965 : or that have no results set, or an OGRLayer pointer representing a results
5966 : set from the query. Note that this OGRLayer is in addition to the layers
5967 : in the data store and must be destroyed with
5968 : ReleaseResultSet() before the dataset is closed
5969 : (destroyed).
5970 :
5971 : This method is the same as the C++ method GDALDataset::ExecuteSQL()
5972 :
5973 : For more information on the SQL dialect supported internally by OGR
5974 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5975 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5976 : to the underlying RDBMS.
5977 :
5978 : Starting with OGR 1.10, the <a
5979 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5980 : also be used.
5981 :
5982 :
5983 : @param hDS the dataset handle.
5984 : @param pszStatement the SQL statement to execute.
5985 : @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5986 :
5987 : @param pszDialect allows control of the statement dialect. If set to NULL, the
5988 : OGR SQL engine will be used, except for RDBMS drivers that will use their
5989 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
5990 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5991 :
5992 : @return an OGRLayer containing the results of the query. Deallocate with
5993 : GDALDatasetReleaseResultSet().
5994 :
5995 : */
5996 :
5997 10638 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5998 : OGRGeometryH hSpatialFilter,
5999 : const char *pszDialect)
6000 :
6001 : {
6002 10638 : VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
6003 :
6004 : OGRLayerH hLayer =
6005 21276 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
6006 10638 : pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
6007 :
6008 : #ifdef OGRAPISPY_ENABLED
6009 10638 : if (bOGRAPISpyEnabled)
6010 4 : OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
6011 : hLayer);
6012 : #endif
6013 :
6014 10638 : return hLayer;
6015 : }
6016 :
6017 : /************************************************************************/
6018 : /* GDALDatasetAbortSQL() */
6019 : /************************************************************************/
6020 :
6021 : /**
6022 : \brief Abort any SQL statement running in the data store.
6023 :
6024 : This function can be safely called from any thread (pending that the dataset
6025 : object is still alive). Driver implementations will make sure that it can be
6026 : called in a thread-safe way.
6027 :
6028 : This might not be implemented by all drivers. At time of writing, only SQLite,
6029 : GPKG and PG drivers implement it
6030 :
6031 : This method is the same as the C++ method GDALDataset::AbortSQL()
6032 :
6033 : @since GDAL 3.2.0
6034 :
6035 : @param hDS the dataset handle.
6036 :
6037 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6038 : is not supported for this datasource. .
6039 :
6040 : */
6041 :
6042 6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6043 :
6044 : {
6045 6 : VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6046 6 : return GDALDataset::FromHandle(hDS)->AbortSQL();
6047 : }
6048 :
6049 : /************************************************************************/
6050 : /* GDALDatasetGetStyleTable() */
6051 : /************************************************************************/
6052 :
6053 : /**
6054 : \brief Returns dataset style table.
6055 :
6056 : This function is the same as the C++ method GDALDataset::GetStyleTable()
6057 :
6058 :
6059 : @param hDS the dataset handle
6060 : @return handle to a style table which should not be modified or freed by the
6061 : caller.
6062 : */
6063 :
6064 6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6065 :
6066 : {
6067 6 : VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6068 :
6069 : return reinterpret_cast<OGRStyleTableH>(
6070 6 : GDALDataset::FromHandle(hDS)->GetStyleTable());
6071 : }
6072 :
6073 : /************************************************************************/
6074 : /* GDALDatasetSetStyleTableDirectly() */
6075 : /************************************************************************/
6076 :
6077 : /**
6078 : \brief Set dataset style table.
6079 :
6080 : This function operate exactly as GDALDatasetSetStyleTable() except that it
6081 : assumes ownership of the passed table.
6082 :
6083 : This function is the same as the C++ method
6084 : GDALDataset::SetStyleTableDirectly()
6085 :
6086 :
6087 : @param hDS the dataset handle
6088 : @param hStyleTable style table handle to set
6089 :
6090 : */
6091 :
6092 0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6093 : OGRStyleTableH hStyleTable)
6094 :
6095 : {
6096 0 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6097 :
6098 0 : GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6099 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6100 : }
6101 :
6102 : /************************************************************************/
6103 : /* GDALDatasetSetStyleTable() */
6104 : /************************************************************************/
6105 :
6106 : /**
6107 : \brief Set dataset style table.
6108 :
6109 : This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6110 : it assumes ownership of the passed table.
6111 :
6112 : This function is the same as the C++ method GDALDataset::SetStyleTable()
6113 :
6114 :
6115 : @param hDS the dataset handle
6116 : @param hStyleTable style table handle to set
6117 :
6118 : */
6119 :
6120 5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6121 :
6122 : {
6123 5 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6124 5 : VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6125 :
6126 5 : GDALDataset::FromHandle(hDS)->SetStyleTable(
6127 5 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6128 : }
6129 :
6130 : /************************************************************************/
6131 : /* ValidateLayerCreationOptions() */
6132 : /************************************************************************/
6133 :
6134 : //! @cond Doxygen_Suppress
6135 10097 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6136 : {
6137 : const char *pszOptionList =
6138 10097 : GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6139 10097 : if (pszOptionList == nullptr && poDriver != nullptr)
6140 : {
6141 : pszOptionList =
6142 10050 : poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6143 : }
6144 20194 : CPLString osDataset;
6145 10097 : osDataset.Printf("dataset %s", GetDescription());
6146 10097 : return GDALValidateOptions(GDALDriver::ToHandle(poDriver), pszOptionList,
6147 20194 : papszLCO, "layer creation option", osDataset);
6148 : }
6149 :
6150 : //! @endcond
6151 :
6152 : /************************************************************************/
6153 : /* Release() */
6154 : /************************************************************************/
6155 :
6156 : /**
6157 : \brief Drop a reference to this dataset, and if the reference count drops to one
6158 : close (destroy) the dataset.
6159 :
6160 : This method is the same as the C function OGRReleaseDataSource().
6161 :
6162 : @deprecated. Use GDALClose() instead
6163 :
6164 : @return OGRERR_NONE on success or an error code.
6165 : */
6166 :
6167 4185 : OGRErr GDALDataset::Release()
6168 :
6169 : {
6170 4185 : ReleaseRef();
6171 4185 : return OGRERR_NONE;
6172 : }
6173 :
6174 : /************************************************************************/
6175 : /* GetRefCount() */
6176 : /************************************************************************/
6177 :
6178 : /**
6179 : \brief Fetch reference count.
6180 :
6181 : This method is the same as the C function OGR_DS_GetRefCount().
6182 :
6183 : @return the current reference count for the datasource object itself.
6184 : */
6185 :
6186 5588 : int GDALDataset::GetRefCount() const
6187 : {
6188 5588 : return nRefCount;
6189 : }
6190 :
6191 : /************************************************************************/
6192 : /* GetSummaryRefCount() */
6193 : /************************************************************************/
6194 :
6195 : /**
6196 : \brief Fetch reference count of datasource and all owned layers.
6197 :
6198 : This method is the same as the C function OGR_DS_GetSummaryRefCount().
6199 :
6200 : @deprecated
6201 :
6202 : @return the current summary reference count for the datasource and its layers.
6203 : */
6204 :
6205 0 : int GDALDataset::GetSummaryRefCount() const
6206 :
6207 : {
6208 0 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6209 0 : int nSummaryCount = nRefCount;
6210 0 : GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6211 :
6212 0 : for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6213 0 : nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6214 :
6215 0 : return nSummaryCount;
6216 : }
6217 :
6218 : /************************************************************************/
6219 : /* ICreateLayer() */
6220 : /************************************************************************/
6221 :
6222 : /**
6223 : \brief This method attempts to create a new layer on the dataset with the
6224 : indicated name, coordinate system, geometry type.
6225 :
6226 : This method is reserved to implementation by drivers.
6227 :
6228 : The papszOptions argument can be used to control driver specific creation
6229 : options. These options are normally documented in the format specific
6230 : documentation.
6231 :
6232 : @param pszName the name for the new layer. This should ideally not
6233 : match any existing layer on the datasource.
6234 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
6235 : or NULL if there is no geometry field.
6236 : @param papszOptions a StringList of name=value options. Options are driver
6237 : specific.
6238 :
6239 : @return NULL is returned on failure, or a new OGRLayer handle on success.
6240 :
6241 : */
6242 :
6243 : OGRLayer *
6244 16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6245 : CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6246 : CPL_UNUSED CSLConstList papszOptions)
6247 :
6248 : {
6249 16 : CPLError(CE_Failure, CPLE_NotSupported,
6250 : "CreateLayer() not supported by this dataset.");
6251 :
6252 16 : return nullptr;
6253 : }
6254 :
6255 : /************************************************************************/
6256 : /* CopyLayer() */
6257 : /************************************************************************/
6258 :
6259 : /**
6260 : \brief Duplicate an existing layer.
6261 :
6262 : This method creates a new layer, duplicate the field definitions of the
6263 : source layer and then duplicate each features of the source layer.
6264 : The papszOptions argument
6265 : can be used to control driver specific creation options. These options are
6266 : normally documented in the format specific documentation.
6267 : The source layer may come from another dataset.
6268 :
6269 : This method is the same as the C function GDALDatasetCopyLayer() and the
6270 : deprecated OGR_DS_CopyLayer().
6271 :
6272 : @param poSrcLayer source layer.
6273 : @param pszNewName the name of the layer to create.
6274 : @param papszOptions a StringList of name=value options. Options are driver
6275 : specific. There is a common option to set output layer
6276 : spatial reference: DST_SRSWKT. The option should be in
6277 : WKT format. Starting with GDAL 3.7, the common option
6278 : COPY_MD can be set to NO to prevent the default copying
6279 : of the metadata from the source layer to the target layer.
6280 :
6281 : @return a handle to the layer, or NULL if an error occurs.
6282 : */
6283 :
6284 192 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6285 : CSLConstList papszOptions)
6286 :
6287 : {
6288 : /* -------------------------------------------------------------------- */
6289 : /* Create the layer. */
6290 : /* -------------------------------------------------------------------- */
6291 192 : if (!TestCapability(ODsCCreateLayer))
6292 : {
6293 0 : CPLError(CE_Failure, CPLE_NotSupported,
6294 : "This datasource does not support creation of layers.");
6295 0 : return nullptr;
6296 : }
6297 :
6298 192 : const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6299 384 : OGRSpatialReference oDstSpaRef(pszSRSWKT);
6300 192 : oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6301 192 : OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6302 192 : OGRLayer *poDstLayer = nullptr;
6303 :
6304 384 : CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6305 192 : aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6306 192 : aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6307 :
6308 192 : CPLErrorReset();
6309 192 : const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6310 192 : if (nSrcGeomFieldCount == 1)
6311 : {
6312 136 : OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6313 136 : if (pszSRSWKT)
6314 5 : oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6315 136 : poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6316 136 : aosCleanedUpOptions.List());
6317 : }
6318 : else
6319 : {
6320 : poDstLayer =
6321 56 : ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6322 : }
6323 :
6324 192 : if (poDstLayer == nullptr)
6325 0 : return nullptr;
6326 :
6327 192 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6328 : {
6329 191 : CSLConstList papszMD = poSrcLayer->GetMetadata();
6330 191 : if (papszMD)
6331 33 : poDstLayer->SetMetadata(papszMD);
6332 : }
6333 :
6334 : /* -------------------------------------------------------------------- */
6335 : /* Add fields. Default to copy all fields, and make sure to */
6336 : /* establish a mapping between indices, rather than names, in */
6337 : /* case the target datasource has altered it (e.g. Shapefile */
6338 : /* limited to 10 char field names). */
6339 : /* -------------------------------------------------------------------- */
6340 192 : const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6341 :
6342 : // Initialize the index-to-index map to -1's.
6343 384 : std::vector<int> anMap(nSrcFieldCount, -1);
6344 :
6345 : // Caution: At the time of writing, the MapInfo driver
6346 : // returns NULL until a field has been added.
6347 192 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6348 192 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6349 517 : for (int iField = 0; iField < nSrcFieldCount; ++iField)
6350 : {
6351 325 : OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6352 650 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6353 :
6354 : // The field may have been already created at layer creation.
6355 325 : int iDstField = -1;
6356 325 : if (poDstFDefn)
6357 325 : iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6358 325 : if (iDstField >= 0)
6359 : {
6360 0 : anMap[iField] = iDstField;
6361 : }
6362 325 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6363 : {
6364 : // Now that we've created a field, GetLayerDefn() won't return NULL.
6365 325 : if (poDstFDefn == nullptr)
6366 0 : poDstFDefn = poDstLayer->GetLayerDefn();
6367 :
6368 : // Sanity check: if it fails, the driver is buggy.
6369 650 : if (poDstFDefn != nullptr &&
6370 325 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6371 : {
6372 0 : CPLError(CE_Warning, CPLE_AppDefined,
6373 : "The output driver has claimed to have added the %s "
6374 : "field, but it did not!",
6375 : oFieldDefn.GetNameRef());
6376 : }
6377 : else
6378 : {
6379 325 : anMap[iField] = nDstFieldCount;
6380 325 : ++nDstFieldCount;
6381 : }
6382 : }
6383 : }
6384 :
6385 : /* -------------------------------------------------------------------- */
6386 192 : std::unique_ptr<OGRCoordinateTransformation> poCT;
6387 192 : const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6388 192 : if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6389 0 : sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6390 : {
6391 0 : poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6392 0 : if (nullptr == poCT)
6393 : {
6394 0 : CPLError(CE_Failure, CPLE_NotSupported,
6395 : "This input/output spatial reference is not supported.");
6396 0 : return nullptr;
6397 : }
6398 : }
6399 : /* -------------------------------------------------------------------- */
6400 : /* Create geometry fields. */
6401 : /* -------------------------------------------------------------------- */
6402 193 : if (nSrcGeomFieldCount > 1 &&
6403 1 : TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6404 : {
6405 :
6406 3 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6407 : {
6408 2 : if (nullptr == pszSRSWKT)
6409 : {
6410 2 : poDstLayer->CreateGeomField(
6411 2 : poSrcDefn->GetGeomFieldDefn(iField));
6412 : }
6413 : else
6414 : {
6415 : OGRGeomFieldDefn *pDstGeomFieldDefn =
6416 0 : poSrcDefn->GetGeomFieldDefn(iField);
6417 0 : pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6418 0 : poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6419 : }
6420 : }
6421 : }
6422 :
6423 : /* -------------------------------------------------------------------- */
6424 : /* Check if the destination layer supports transactions and set a */
6425 : /* default number of features in a single transaction. */
6426 : /* -------------------------------------------------------------------- */
6427 : const int nGroupTransactions =
6428 192 : poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6429 :
6430 : /* -------------------------------------------------------------------- */
6431 : /* Transfer features. */
6432 : /* -------------------------------------------------------------------- */
6433 192 : poSrcLayer->ResetReading();
6434 :
6435 192 : if (nGroupTransactions <= 0)
6436 : {
6437 : while (true)
6438 : {
6439 : auto poFeature =
6440 748 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6441 :
6442 748 : if (poFeature == nullptr)
6443 183 : break;
6444 :
6445 565 : CPLErrorReset();
6446 : auto poDstFeature =
6447 565 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6448 :
6449 565 : if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6450 : OGRERR_NONE)
6451 : {
6452 0 : CPLError(CE_Failure, CPLE_AppDefined,
6453 : "Unable to translate feature " CPL_FRMT_GIB
6454 : " from layer %s.",
6455 0 : poFeature->GetFID(), poSrcDefn->GetName());
6456 0 : return poDstLayer;
6457 : }
6458 :
6459 565 : if (nullptr != poCT)
6460 : {
6461 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6462 : {
6463 0 : OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6464 0 : if (nullptr == pGeom)
6465 0 : continue;
6466 :
6467 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6468 0 : if (eErr == OGRERR_NONE)
6469 0 : continue;
6470 :
6471 0 : CPLError(CE_Failure, CPLE_AppDefined,
6472 : "Unable to transform geometry " CPL_FRMT_GIB
6473 : " from layer %s.",
6474 0 : poFeature->GetFID(), poSrcDefn->GetName());
6475 0 : return poDstLayer;
6476 : }
6477 : }
6478 :
6479 565 : poDstFeature->SetFID(poFeature->GetFID());
6480 :
6481 565 : CPLErrorReset();
6482 565 : if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6483 : {
6484 0 : return poDstLayer;
6485 : }
6486 565 : }
6487 : }
6488 : else
6489 : {
6490 9 : std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6491 : try
6492 : {
6493 9 : apoDstFeatures.resize(nGroupTransactions);
6494 : }
6495 0 : catch (const std::exception &e)
6496 : {
6497 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6498 0 : return poDstLayer;
6499 : }
6500 9 : bool bStopTransfer = false;
6501 18 : while (!bStopTransfer)
6502 : {
6503 : /* --------------------------------------------------------------------
6504 : */
6505 : /* Fill the array with features. */
6506 : /* --------------------------------------------------------------------
6507 : */
6508 : // Number of features in the temporary array.
6509 9 : int nFeatCount = 0; // Used after for.
6510 85 : for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6511 : {
6512 : auto poFeature =
6513 85 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6514 :
6515 85 : if (poFeature == nullptr)
6516 : {
6517 9 : bStopTransfer = true;
6518 9 : break;
6519 : }
6520 :
6521 76 : CPLErrorReset();
6522 76 : apoDstFeatures[nFeatCount] =
6523 152 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6524 :
6525 152 : if (apoDstFeatures[nFeatCount]->SetFrom(
6526 152 : poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6527 : {
6528 0 : CPLError(CE_Failure, CPLE_AppDefined,
6529 : "Unable to translate feature " CPL_FRMT_GIB
6530 : " from layer %s.",
6531 0 : poFeature->GetFID(), poSrcDefn->GetName());
6532 0 : bStopTransfer = true;
6533 0 : poFeature.reset();
6534 0 : break;
6535 : }
6536 :
6537 76 : if (nullptr != poCT)
6538 : {
6539 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6540 : {
6541 : OGRGeometry *pGeom =
6542 0 : apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6543 0 : if (nullptr == pGeom)
6544 0 : continue;
6545 :
6546 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6547 0 : if (eErr == OGRERR_NONE)
6548 0 : continue;
6549 :
6550 0 : CPLError(CE_Failure, CPLE_AppDefined,
6551 : "Unable to transform geometry " CPL_FRMT_GIB
6552 : " from layer %s.",
6553 0 : poFeature->GetFID(), poSrcDefn->GetName());
6554 0 : bStopTransfer = true;
6555 0 : poFeature.reset();
6556 0 : break;
6557 : }
6558 : }
6559 :
6560 76 : if (poFeature)
6561 : {
6562 76 : apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6563 : }
6564 : }
6565 :
6566 9 : CPLErrorReset();
6567 9 : bool bStopTransaction = false;
6568 18 : while (!bStopTransaction)
6569 : {
6570 9 : bStopTransaction = true;
6571 9 : if (poDstLayer->StartTransaction() != OGRERR_NONE)
6572 0 : break;
6573 85 : for (int i = 0; i < nFeatCount; ++i)
6574 : {
6575 76 : if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6576 : OGRERR_NONE)
6577 : {
6578 0 : bStopTransfer = true;
6579 0 : bStopTransaction = false;
6580 0 : break;
6581 : }
6582 76 : apoDstFeatures[i].reset();
6583 : }
6584 9 : if (bStopTransaction)
6585 : {
6586 9 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6587 0 : break;
6588 : }
6589 : else
6590 : {
6591 0 : poDstLayer->RollbackTransaction();
6592 : }
6593 : }
6594 : }
6595 : }
6596 :
6597 192 : return poDstLayer;
6598 : }
6599 :
6600 : /************************************************************************/
6601 : /* DeleteLayer() */
6602 : /************************************************************************/
6603 :
6604 : /**
6605 : \fn GDALDataset::DeleteLayer(int)
6606 : \brief Delete the indicated layer from the datasource.
6607 :
6608 : If this method is supported
6609 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6610 :
6611 : This method is the same as the C function GDALDatasetDeleteLayer() and the
6612 : deprecated OGR_DS_DeleteLayer().
6613 :
6614 : @param iLayer the index of the layer to delete.
6615 :
6616 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6617 : layers is not supported for this datasource.
6618 :
6619 : */
6620 :
6621 389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6622 :
6623 : {
6624 389 : CPLError(CE_Failure, CPLE_NotSupported,
6625 : "DeleteLayer() not supported by this dataset.");
6626 :
6627 389 : return OGRERR_UNSUPPORTED_OPERATION;
6628 : }
6629 :
6630 : /************************************************************************/
6631 : /* GetLayerByName() */
6632 : /************************************************************************/
6633 :
6634 : /**
6635 : \brief Fetch a layer by name.
6636 :
6637 : The returned layer remains owned by the
6638 : GDALDataset and should not be deleted by the application.
6639 :
6640 : This method is the same as the C function GDALDatasetGetLayerByName() and the
6641 : deprecated OGR_DS_GetLayerByName().
6642 :
6643 : @param pszName the layer name of the layer to fetch.
6644 :
6645 : @return the layer, or NULL if Layer is not found or an error occurs.
6646 : */
6647 :
6648 32268 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6649 :
6650 : {
6651 64536 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6652 :
6653 32268 : if (!pszName)
6654 5 : return nullptr;
6655 :
6656 : // First a case sensitive check.
6657 939109 : for (auto *poLayer : GetLayers())
6658 : {
6659 920624 : if (strcmp(pszName, poLayer->GetName()) == 0)
6660 13778 : return poLayer;
6661 : }
6662 :
6663 : // Then case insensitive.
6664 894242 : for (auto *poLayer : GetLayers())
6665 : {
6666 875981 : if (EQUAL(pszName, poLayer->GetName()))
6667 224 : return poLayer;
6668 : }
6669 :
6670 18261 : return nullptr;
6671 : }
6672 :
6673 : //! @cond Doxygen_Suppress
6674 : /************************************************************************/
6675 : /* ProcessSQLCreateIndex() */
6676 : /* */
6677 : /* The correct syntax for creating an index in our dialect of */
6678 : /* SQL is: */
6679 : /* */
6680 : /* CREATE INDEX ON <layername> USING <columnname> */
6681 : /************************************************************************/
6682 :
6683 28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6684 :
6685 : {
6686 28 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6687 :
6688 : /* -------------------------------------------------------------------- */
6689 : /* Do some general syntax checking. */
6690 : /* -------------------------------------------------------------------- */
6691 56 : if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6692 84 : !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6693 28 : !EQUAL(papszTokens[4], "USING"))
6694 : {
6695 0 : CSLDestroy(papszTokens);
6696 0 : CPLError(CE_Failure, CPLE_AppDefined,
6697 : "Syntax error in CREATE INDEX command.\n"
6698 : "Was '%s'\n"
6699 : "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6700 : pszSQLCommand);
6701 0 : return OGRERR_FAILURE;
6702 : }
6703 :
6704 : /* -------------------------------------------------------------------- */
6705 : /* Find the named layer. */
6706 : /* -------------------------------------------------------------------- */
6707 28 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6708 28 : if (poLayer == nullptr)
6709 : {
6710 0 : CPLError(CE_Failure, CPLE_AppDefined,
6711 : "CREATE INDEX ON failed, no such layer as `%s'.",
6712 0 : papszTokens[3]);
6713 0 : CSLDestroy(papszTokens);
6714 0 : return OGRERR_FAILURE;
6715 : }
6716 :
6717 : /* -------------------------------------------------------------------- */
6718 : /* Does this layer even support attribute indexes? */
6719 : /* -------------------------------------------------------------------- */
6720 28 : if (poLayer->GetIndex() == nullptr)
6721 : {
6722 0 : CPLError(CE_Failure, CPLE_AppDefined,
6723 : "CREATE INDEX ON not supported by this driver.");
6724 0 : CSLDestroy(papszTokens);
6725 0 : return OGRERR_FAILURE;
6726 : }
6727 :
6728 : /* -------------------------------------------------------------------- */
6729 : /* Find the named field. */
6730 : /* -------------------------------------------------------------------- */
6731 28 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6732 :
6733 28 : CSLDestroy(papszTokens);
6734 :
6735 28 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6736 : {
6737 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6738 : pszSQLCommand);
6739 0 : return OGRERR_FAILURE;
6740 : }
6741 :
6742 : /* -------------------------------------------------------------------- */
6743 : /* Attempt to create the index. */
6744 : /* -------------------------------------------------------------------- */
6745 28 : OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6746 28 : if (eErr == OGRERR_NONE)
6747 : {
6748 28 : eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6749 : }
6750 : else
6751 : {
6752 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
6753 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6754 : }
6755 :
6756 28 : return eErr;
6757 : }
6758 :
6759 : /************************************************************************/
6760 : /* ProcessSQLDropIndex() */
6761 : /* */
6762 : /* The correct syntax for dropping one or more indexes in */
6763 : /* the OGR SQL dialect is: */
6764 : /* */
6765 : /* DROP INDEX ON <layername> [USING <columnname>] */
6766 : /************************************************************************/
6767 :
6768 10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6769 :
6770 : {
6771 10 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6772 :
6773 : /* -------------------------------------------------------------------- */
6774 : /* Do some general syntax checking. */
6775 : /* -------------------------------------------------------------------- */
6776 20 : if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6777 10 : !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6778 30 : !EQUAL(papszTokens[2], "ON") ||
6779 10 : (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6780 : {
6781 0 : CSLDestroy(papszTokens);
6782 0 : CPLError(CE_Failure, CPLE_AppDefined,
6783 : "Syntax error in DROP INDEX command.\n"
6784 : "Was '%s'\n"
6785 : "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6786 : pszSQLCommand);
6787 0 : return OGRERR_FAILURE;
6788 : }
6789 :
6790 : /* -------------------------------------------------------------------- */
6791 : /* Find the named layer. */
6792 : /* -------------------------------------------------------------------- */
6793 10 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6794 10 : if (poLayer == nullptr)
6795 : {
6796 0 : CPLError(CE_Failure, CPLE_AppDefined,
6797 : "DROP INDEX ON failed, no such layer as `%s'.",
6798 0 : papszTokens[3]);
6799 0 : CSLDestroy(papszTokens);
6800 0 : return OGRERR_FAILURE;
6801 : }
6802 :
6803 : /* -------------------------------------------------------------------- */
6804 : /* Does this layer even support attribute indexes? */
6805 : /* -------------------------------------------------------------------- */
6806 10 : if (poLayer->GetIndex() == nullptr)
6807 : {
6808 0 : CPLError(CE_Failure, CPLE_AppDefined,
6809 : "Indexes not supported by this driver.");
6810 0 : CSLDestroy(papszTokens);
6811 0 : return OGRERR_FAILURE;
6812 : }
6813 :
6814 : /* -------------------------------------------------------------------- */
6815 : /* If we were not given a field name, drop all indexes. */
6816 : /* -------------------------------------------------------------------- */
6817 10 : if (CSLCount(papszTokens) == 4)
6818 : {
6819 0 : for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6820 : {
6821 : OGRAttrIndex *poAttrIndex;
6822 :
6823 0 : poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6824 0 : if (poAttrIndex != nullptr)
6825 : {
6826 0 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6827 0 : if (eErr != OGRERR_NONE)
6828 : {
6829 0 : CSLDestroy(papszTokens);
6830 0 : return eErr;
6831 : }
6832 : }
6833 : }
6834 :
6835 0 : CSLDestroy(papszTokens);
6836 0 : return OGRERR_NONE;
6837 : }
6838 :
6839 : /* -------------------------------------------------------------------- */
6840 : /* Find the named field. */
6841 : /* -------------------------------------------------------------------- */
6842 10 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6843 10 : CSLDestroy(papszTokens);
6844 :
6845 10 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6846 : {
6847 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6848 : pszSQLCommand);
6849 0 : return OGRERR_FAILURE;
6850 : }
6851 :
6852 : /* -------------------------------------------------------------------- */
6853 : /* Attempt to drop the index. */
6854 : /* -------------------------------------------------------------------- */
6855 10 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6856 :
6857 10 : return eErr;
6858 : }
6859 :
6860 : /************************************************************************/
6861 : /* ProcessSQLDropTable() */
6862 : /* */
6863 : /* The correct syntax for dropping a table (layer) in the OGR SQL */
6864 : /* dialect is: */
6865 : /* */
6866 : /* DROP TABLE <layername> */
6867 : /************************************************************************/
6868 :
6869 500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6870 :
6871 : {
6872 500 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6873 :
6874 : /* -------------------------------------------------------------------- */
6875 : /* Do some general syntax checking. */
6876 : /* -------------------------------------------------------------------- */
6877 1000 : if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6878 500 : !EQUAL(papszTokens[1], "TABLE"))
6879 : {
6880 0 : CSLDestroy(papszTokens);
6881 0 : CPLError(CE_Failure, CPLE_AppDefined,
6882 : "Syntax error in DROP TABLE command.\n"
6883 : "Was '%s'\n"
6884 : "Should be of form 'DROP TABLE <table>'",
6885 : pszSQLCommand);
6886 0 : return OGRERR_FAILURE;
6887 : }
6888 :
6889 : /* -------------------------------------------------------------------- */
6890 : /* Find the named layer. */
6891 : /* -------------------------------------------------------------------- */
6892 500 : OGRLayer *poLayer = nullptr;
6893 :
6894 500 : int i = 0; // Used after for.
6895 40199 : for (; i < GetLayerCount(); ++i)
6896 : {
6897 40199 : poLayer = GetLayer(i);
6898 :
6899 40199 : if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6900 500 : break;
6901 39699 : poLayer = nullptr;
6902 : }
6903 :
6904 500 : if (poLayer == nullptr)
6905 : {
6906 0 : CPLError(CE_Failure, CPLE_AppDefined,
6907 0 : "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6908 0 : CSLDestroy(papszTokens);
6909 0 : return OGRERR_FAILURE;
6910 : }
6911 :
6912 500 : CSLDestroy(papszTokens);
6913 :
6914 : /* -------------------------------------------------------------------- */
6915 : /* Delete it. */
6916 : /* -------------------------------------------------------------------- */
6917 :
6918 500 : return DeleteLayer(i);
6919 : }
6920 :
6921 : //! @endcond
6922 :
6923 : /************************************************************************/
6924 : /* GDALDatasetParseSQLType() */
6925 : /************************************************************************/
6926 :
6927 : /* All arguments will be altered */
6928 6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6929 : int &nPrecision)
6930 : {
6931 6 : char *pszParenthesis = strchr(pszType, '(');
6932 6 : if (pszParenthesis)
6933 : {
6934 4 : nWidth = atoi(pszParenthesis + 1);
6935 4 : *pszParenthesis = '\0';
6936 4 : char *pszComma = strchr(pszParenthesis + 1, ',');
6937 4 : if (pszComma)
6938 2 : nPrecision = atoi(pszComma + 1);
6939 : }
6940 :
6941 6 : OGRFieldType eType = OFTString;
6942 6 : if (EQUAL(pszType, "INTEGER"))
6943 0 : eType = OFTInteger;
6944 6 : else if (EQUAL(pszType, "INTEGER[]"))
6945 0 : eType = OFTIntegerList;
6946 6 : else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6947 4 : EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6948 4 : EQUAL(pszType, "REAL") /* unofficial alias */)
6949 2 : eType = OFTReal;
6950 4 : else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6951 4 : EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6952 4 : EQUAL(pszType, "REAL[]") /* unofficial alias */)
6953 0 : eType = OFTRealList;
6954 4 : else if (EQUAL(pszType, "CHARACTER") ||
6955 0 : EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6956 0 : EQUAL(pszType, "STRING") /* unofficial alias */ ||
6957 0 : EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6958 4 : eType = OFTString;
6959 0 : else if (EQUAL(pszType, "TEXT[]") ||
6960 0 : EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6961 0 : EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6962 0 : eType = OFTStringList;
6963 0 : else if (EQUAL(pszType, "DATE"))
6964 0 : eType = OFTDate;
6965 0 : else if (EQUAL(pszType, "TIME"))
6966 0 : eType = OFTTime;
6967 0 : else if (EQUAL(pszType, "TIMESTAMP") ||
6968 0 : EQUAL(pszType, "DATETIME") /* unofficial alias */)
6969 0 : eType = OFTDateTime;
6970 : else
6971 0 : CPLError(CE_Warning, CPLE_NotSupported,
6972 : "Unsupported column type '%s'. Defaulting to VARCHAR",
6973 : pszType);
6974 :
6975 6 : return eType;
6976 : }
6977 :
6978 : /************************************************************************/
6979 : /* ProcessSQLAlterTableAddColumn() */
6980 : /* */
6981 : /* The correct syntax for adding a column in the OGR SQL */
6982 : /* dialect is: */
6983 : /* */
6984 : /* ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6985 : /************************************************************************/
6986 :
6987 : //! @cond Doxygen_Suppress
6988 2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6989 :
6990 : {
6991 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6992 :
6993 : /* -------------------------------------------------------------------- */
6994 : /* Do some general syntax checking. */
6995 : /* -------------------------------------------------------------------- */
6996 2 : const char *pszLayerName = nullptr;
6997 2 : const char *pszColumnName = nullptr;
6998 2 : int iTypeIndex = 0;
6999 2 : const int nTokens = CSLCount(papszTokens);
7000 :
7001 2 : if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7002 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
7003 2 : EQUAL(papszTokens[4], "COLUMN"))
7004 : {
7005 1 : pszLayerName = papszTokens[2];
7006 1 : pszColumnName = papszTokens[5];
7007 1 : iTypeIndex = 6;
7008 : }
7009 1 : else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
7010 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
7011 : {
7012 1 : pszLayerName = papszTokens[2];
7013 1 : pszColumnName = papszTokens[4];
7014 1 : iTypeIndex = 5;
7015 : }
7016 : else
7017 : {
7018 0 : CSLDestroy(papszTokens);
7019 0 : CPLError(CE_Failure, CPLE_AppDefined,
7020 : "Syntax error in ALTER TABLE ADD COLUMN command.\n"
7021 : "Was '%s'\n"
7022 : "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
7023 : "<columnname> <columntype>'",
7024 : pszSQLCommand);
7025 0 : return OGRERR_FAILURE;
7026 : }
7027 :
7028 : /* -------------------------------------------------------------------- */
7029 : /* Merge type components into a single string if there were split */
7030 : /* with spaces */
7031 : /* -------------------------------------------------------------------- */
7032 4 : CPLString osType;
7033 6 : for (int i = iTypeIndex; i < nTokens; ++i)
7034 : {
7035 4 : osType += papszTokens[i];
7036 4 : CPLFree(papszTokens[i]);
7037 : }
7038 2 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7039 2 : papszTokens[iTypeIndex + 1] = nullptr;
7040 :
7041 : /* -------------------------------------------------------------------- */
7042 : /* Find the named layer. */
7043 : /* -------------------------------------------------------------------- */
7044 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7045 2 : if (poLayer == nullptr)
7046 : {
7047 0 : CPLError(CE_Failure, CPLE_AppDefined,
7048 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7049 : pszLayerName);
7050 0 : CSLDestroy(papszTokens);
7051 0 : return OGRERR_FAILURE;
7052 : }
7053 :
7054 : /* -------------------------------------------------------------------- */
7055 : /* Add column. */
7056 : /* -------------------------------------------------------------------- */
7057 :
7058 2 : int nWidth = 0;
7059 2 : int nPrecision = 0;
7060 2 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7061 4 : OGRFieldDefn oFieldDefn(pszColumnName, eType);
7062 2 : oFieldDefn.SetWidth(nWidth);
7063 2 : oFieldDefn.SetPrecision(nPrecision);
7064 :
7065 2 : CSLDestroy(papszTokens);
7066 :
7067 2 : return poLayer->CreateField(&oFieldDefn);
7068 : }
7069 :
7070 : /************************************************************************/
7071 : /* ProcessSQLAlterTableDropColumn() */
7072 : /* */
7073 : /* The correct syntax for dropping a column in the OGR SQL */
7074 : /* dialect is: */
7075 : /* */
7076 : /* ALTER TABLE <layername> DROP [COLUMN] <columnname> */
7077 : /************************************************************************/
7078 :
7079 2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7080 :
7081 : {
7082 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7083 :
7084 : /* -------------------------------------------------------------------- */
7085 : /* Do some general syntax checking. */
7086 : /* -------------------------------------------------------------------- */
7087 2 : const char *pszLayerName = nullptr;
7088 2 : const char *pszColumnName = nullptr;
7089 3 : if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7090 4 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7091 1 : EQUAL(papszTokens[4], "COLUMN"))
7092 : {
7093 1 : pszLayerName = papszTokens[2];
7094 1 : pszColumnName = papszTokens[5];
7095 : }
7096 2 : else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7097 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7098 : {
7099 1 : pszLayerName = papszTokens[2];
7100 1 : pszColumnName = papszTokens[4];
7101 : }
7102 : else
7103 : {
7104 0 : CSLDestroy(papszTokens);
7105 0 : CPLError(CE_Failure, CPLE_AppDefined,
7106 : "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7107 : "Was '%s'\n"
7108 : "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7109 : "<columnname>'",
7110 : pszSQLCommand);
7111 0 : return OGRERR_FAILURE;
7112 : }
7113 :
7114 : /* -------------------------------------------------------------------- */
7115 : /* Find the named layer. */
7116 : /* -------------------------------------------------------------------- */
7117 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7118 2 : if (poLayer == nullptr)
7119 : {
7120 0 : CPLError(CE_Failure, CPLE_AppDefined,
7121 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7122 : pszLayerName);
7123 0 : CSLDestroy(papszTokens);
7124 0 : return OGRERR_FAILURE;
7125 : }
7126 :
7127 : /* -------------------------------------------------------------------- */
7128 : /* Find the field. */
7129 : /* -------------------------------------------------------------------- */
7130 :
7131 2 : int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7132 2 : if (nFieldIndex < 0)
7133 : {
7134 0 : CPLError(CE_Failure, CPLE_AppDefined,
7135 : "%s failed, no such field as `%s'.", pszSQLCommand,
7136 : pszColumnName);
7137 0 : CSLDestroy(papszTokens);
7138 0 : return OGRERR_FAILURE;
7139 : }
7140 :
7141 : /* -------------------------------------------------------------------- */
7142 : /* Remove it. */
7143 : /* -------------------------------------------------------------------- */
7144 :
7145 2 : CSLDestroy(papszTokens);
7146 :
7147 2 : return poLayer->DeleteField(nFieldIndex);
7148 : }
7149 :
7150 : /************************************************************************/
7151 : /* ProcessSQLAlterTableRenameColumn() */
7152 : /* */
7153 : /* The correct syntax for renaming a column in the OGR SQL */
7154 : /* dialect is: */
7155 : /* */
7156 : /* ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7157 : /************************************************************************/
7158 :
7159 2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7160 :
7161 : {
7162 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7163 :
7164 : /* -------------------------------------------------------------------- */
7165 : /* Do some general syntax checking. */
7166 : /* -------------------------------------------------------------------- */
7167 2 : const char *pszLayerName = nullptr;
7168 2 : const char *pszOldColName = nullptr;
7169 2 : const char *pszNewColName = nullptr;
7170 3 : if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7171 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7172 3 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7173 : {
7174 1 : pszLayerName = papszTokens[2];
7175 1 : pszOldColName = papszTokens[5];
7176 1 : pszNewColName = papszTokens[7];
7177 : }
7178 2 : else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7179 1 : EQUAL(papszTokens[1], "TABLE") &&
7180 2 : EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7181 : {
7182 1 : pszLayerName = papszTokens[2];
7183 1 : pszOldColName = papszTokens[4];
7184 1 : pszNewColName = papszTokens[6];
7185 : }
7186 : else
7187 : {
7188 0 : CSLDestroy(papszTokens);
7189 0 : CPLError(CE_Failure, CPLE_AppDefined,
7190 : "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7191 : "Was '%s'\n"
7192 : "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7193 : "<columnname> TO <newname>'",
7194 : pszSQLCommand);
7195 0 : return OGRERR_FAILURE;
7196 : }
7197 :
7198 : /* -------------------------------------------------------------------- */
7199 : /* Find the named layer. */
7200 : /* -------------------------------------------------------------------- */
7201 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7202 2 : if (poLayer == nullptr)
7203 : {
7204 0 : CPLError(CE_Failure, CPLE_AppDefined,
7205 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7206 : pszLayerName);
7207 0 : CSLDestroy(papszTokens);
7208 0 : return OGRERR_FAILURE;
7209 : }
7210 :
7211 : /* -------------------------------------------------------------------- */
7212 : /* Find the field. */
7213 : /* -------------------------------------------------------------------- */
7214 :
7215 : const int nFieldIndex =
7216 2 : poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7217 2 : if (nFieldIndex < 0)
7218 : {
7219 0 : CPLError(CE_Failure, CPLE_AppDefined,
7220 : "%s failed, no such field as `%s'.", pszSQLCommand,
7221 : pszOldColName);
7222 0 : CSLDestroy(papszTokens);
7223 0 : return OGRERR_FAILURE;
7224 : }
7225 :
7226 : /* -------------------------------------------------------------------- */
7227 : /* Rename column. */
7228 : /* -------------------------------------------------------------------- */
7229 : OGRFieldDefn *poOldFieldDefn =
7230 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7231 4 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7232 2 : oNewFieldDefn.SetName(pszNewColName);
7233 :
7234 2 : CSLDestroy(papszTokens);
7235 :
7236 2 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7237 2 : ALTER_NAME_FLAG);
7238 : }
7239 :
7240 : /************************************************************************/
7241 : /* ProcessSQLAlterTableAlterColumn() */
7242 : /* */
7243 : /* The correct syntax for altering the type of a column in the */
7244 : /* OGR SQL dialect is: */
7245 : /* */
7246 : /* ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7247 : /************************************************************************/
7248 :
7249 4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7250 :
7251 : {
7252 4 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7253 :
7254 : /* -------------------------------------------------------------------- */
7255 : /* Do some general syntax checking. */
7256 : /* -------------------------------------------------------------------- */
7257 4 : const char *pszLayerName = nullptr;
7258 4 : const char *pszColumnName = nullptr;
7259 4 : int iTypeIndex = 0;
7260 4 : const int nTokens = CSLCount(papszTokens);
7261 :
7262 4 : if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7263 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7264 2 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7265 : {
7266 2 : pszLayerName = papszTokens[2];
7267 2 : pszColumnName = papszTokens[5];
7268 2 : iTypeIndex = 7;
7269 : }
7270 2 : else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7271 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7272 2 : EQUAL(papszTokens[5], "TYPE"))
7273 : {
7274 2 : pszLayerName = papszTokens[2];
7275 2 : pszColumnName = papszTokens[4];
7276 2 : iTypeIndex = 6;
7277 : }
7278 : else
7279 : {
7280 0 : CSLDestroy(papszTokens);
7281 0 : CPLError(CE_Failure, CPLE_AppDefined,
7282 : "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7283 : "Was '%s'\n"
7284 : "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7285 : "<columnname> TYPE <columntype>'",
7286 : pszSQLCommand);
7287 0 : return OGRERR_FAILURE;
7288 : }
7289 :
7290 : /* -------------------------------------------------------------------- */
7291 : /* Merge type components into a single string if there were split */
7292 : /* with spaces */
7293 : /* -------------------------------------------------------------------- */
7294 8 : CPLString osType;
7295 8 : for (int i = iTypeIndex; i < nTokens; ++i)
7296 : {
7297 4 : osType += papszTokens[i];
7298 4 : CPLFree(papszTokens[i]);
7299 : }
7300 4 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7301 4 : papszTokens[iTypeIndex + 1] = nullptr;
7302 :
7303 : /* -------------------------------------------------------------------- */
7304 : /* Find the named layer. */
7305 : /* -------------------------------------------------------------------- */
7306 4 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7307 4 : if (poLayer == nullptr)
7308 : {
7309 0 : CPLError(CE_Failure, CPLE_AppDefined,
7310 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7311 : pszLayerName);
7312 0 : CSLDestroy(papszTokens);
7313 0 : return OGRERR_FAILURE;
7314 : }
7315 :
7316 : /* -------------------------------------------------------------------- */
7317 : /* Find the field. */
7318 : /* -------------------------------------------------------------------- */
7319 :
7320 : const int nFieldIndex =
7321 4 : poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7322 4 : if (nFieldIndex < 0)
7323 : {
7324 0 : CPLError(CE_Failure, CPLE_AppDefined,
7325 : "%s failed, no such field as `%s'.", pszSQLCommand,
7326 : pszColumnName);
7327 0 : CSLDestroy(papszTokens);
7328 0 : return OGRERR_FAILURE;
7329 : }
7330 :
7331 : /* -------------------------------------------------------------------- */
7332 : /* Alter column. */
7333 : /* -------------------------------------------------------------------- */
7334 :
7335 : OGRFieldDefn *poOldFieldDefn =
7336 4 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7337 8 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7338 :
7339 4 : int nWidth = 0;
7340 4 : int nPrecision = 0;
7341 4 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7342 4 : oNewFieldDefn.SetType(eType);
7343 4 : oNewFieldDefn.SetWidth(nWidth);
7344 4 : oNewFieldDefn.SetPrecision(nPrecision);
7345 :
7346 4 : int l_nFlags = 0;
7347 4 : if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7348 2 : l_nFlags |= ALTER_TYPE_FLAG;
7349 4 : if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7350 0 : poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7351 4 : l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7352 :
7353 4 : CSLDestroy(papszTokens);
7354 :
7355 4 : if (l_nFlags == 0)
7356 0 : return OGRERR_NONE;
7357 :
7358 4 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7359 : }
7360 :
7361 : //! @endcond
7362 :
7363 : /************************************************************************/
7364 : /* ExecuteSQL() */
7365 : /************************************************************************/
7366 :
7367 : /**
7368 : \brief Execute an SQL statement against the data store.
7369 :
7370 : The result of an SQL query is either NULL for statements that are in error,
7371 : or that have no results set, or an OGRLayer pointer representing a results
7372 : set from the query. Note that this OGRLayer is in addition to the layers
7373 : in the data store and must be destroyed with
7374 : ReleaseResultSet() before the dataset is closed
7375 : (destroyed).
7376 :
7377 : This method is the same as the C function GDALDatasetExecuteSQL() and the
7378 : deprecated OGR_DS_ExecuteSQL().
7379 :
7380 : For more information on the SQL dialect supported internally by OGR
7381 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7382 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7383 : to the underlying RDBMS.
7384 :
7385 : Starting with OGR 1.10, the <a
7386 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7387 : also be used.
7388 :
7389 : @param pszStatement the SQL statement to execute.
7390 : @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7391 : @param pszDialect allows control of the statement dialect. If set to NULL, the
7392 : OGR SQL engine will be used, except for RDBMS drivers that will use their
7393 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
7394 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7395 :
7396 : @return an OGRLayer containing the results of the query. Deallocate with
7397 : ReleaseResultSet().
7398 :
7399 : */
7400 :
7401 4063 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7402 : OGRGeometry *poSpatialFilter,
7403 : const char *pszDialect)
7404 :
7405 : {
7406 4063 : return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7407 : }
7408 :
7409 : //! @cond Doxygen_Suppress
7410 : OGRLayer *
7411 4071 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7412 : const char *pszDialect,
7413 : swq_select_parse_options *poSelectParseOptions)
7414 :
7415 : {
7416 4071 : if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7417 : {
7418 : #ifdef SQLITE_ENABLED
7419 672 : return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7420 672 : pszDialect);
7421 : #else
7422 : CPLError(CE_Failure, CPLE_NotSupported,
7423 : "The SQLite driver needs to be compiled to support the "
7424 : "SQLite SQL dialect");
7425 : return nullptr;
7426 : #endif
7427 : }
7428 :
7429 3399 : if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7430 14 : !EQUAL(pszDialect, "OGRSQL"))
7431 : {
7432 6 : std::string osDialectList = "'OGRSQL'";
7433 : #ifdef SQLITE_ENABLED
7434 3 : osDialectList += ", 'SQLITE'";
7435 : #endif
7436 : const char *pszDialects =
7437 3 : GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7438 3 : if (pszDialects)
7439 : {
7440 : const CPLStringList aosTokens(
7441 0 : CSLTokenizeString2(pszDialects, " ", 0));
7442 0 : for (int i = 0; i < aosTokens.size(); ++i)
7443 : {
7444 0 : if (!EQUAL(aosTokens[i], "OGRSQL") &&
7445 0 : !EQUAL(aosTokens[i], "SQLITE"))
7446 : {
7447 0 : osDialectList += ", '";
7448 0 : osDialectList += aosTokens[i];
7449 0 : osDialectList += "'";
7450 : }
7451 : }
7452 : }
7453 3 : CPLError(CE_Warning, CPLE_NotSupported,
7454 : "Dialect '%s' is unsupported. Only supported dialects are %s. "
7455 : "Defaulting to OGRSQL",
7456 : pszDialect, osDialectList.c_str());
7457 : }
7458 :
7459 : /* -------------------------------------------------------------------- */
7460 : /* Handle CREATE INDEX statements specially. */
7461 : /* -------------------------------------------------------------------- */
7462 3399 : if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7463 : {
7464 28 : ProcessSQLCreateIndex(pszStatement);
7465 28 : return nullptr;
7466 : }
7467 :
7468 : /* -------------------------------------------------------------------- */
7469 : /* Handle DROP INDEX statements specially. */
7470 : /* -------------------------------------------------------------------- */
7471 3371 : if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7472 : {
7473 10 : ProcessSQLDropIndex(pszStatement);
7474 10 : return nullptr;
7475 : }
7476 :
7477 : /* -------------------------------------------------------------------- */
7478 : /* Handle DROP TABLE statements specially. */
7479 : /* -------------------------------------------------------------------- */
7480 3361 : if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7481 : {
7482 500 : ProcessSQLDropTable(pszStatement);
7483 500 : return nullptr;
7484 : }
7485 :
7486 : /* -------------------------------------------------------------------- */
7487 : /* Handle ALTER TABLE statements specially. */
7488 : /* -------------------------------------------------------------------- */
7489 2861 : if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7490 : {
7491 11 : char **papszTokens = CSLTokenizeString(pszStatement);
7492 11 : const int nTokens = CSLCount(papszTokens);
7493 11 : if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7494 : {
7495 2 : ProcessSQLAlterTableAddColumn(pszStatement);
7496 2 : CSLDestroy(papszTokens);
7497 2 : return nullptr;
7498 : }
7499 9 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7500 : {
7501 2 : ProcessSQLAlterTableDropColumn(pszStatement);
7502 2 : CSLDestroy(papszTokens);
7503 2 : return nullptr;
7504 : }
7505 7 : else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7506 1 : EQUAL(papszTokens[4], "TO"))
7507 : {
7508 1 : const char *pszSrcTableName = papszTokens[2];
7509 1 : const char *pszDstTableName = papszTokens[5];
7510 1 : auto poSrcLayer = GetLayerByName(pszSrcTableName);
7511 1 : if (poSrcLayer)
7512 : {
7513 1 : CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7514 : }
7515 : else
7516 : {
7517 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7518 : }
7519 1 : CSLDestroy(papszTokens);
7520 1 : return nullptr;
7521 : }
7522 6 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7523 : {
7524 2 : ProcessSQLAlterTableRenameColumn(pszStatement);
7525 2 : CSLDestroy(papszTokens);
7526 2 : return nullptr;
7527 : }
7528 4 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7529 : {
7530 4 : ProcessSQLAlterTableAlterColumn(pszStatement);
7531 4 : CSLDestroy(papszTokens);
7532 4 : return nullptr;
7533 : }
7534 : else
7535 : {
7536 0 : CPLError(CE_Failure, CPLE_AppDefined,
7537 : "Unsupported ALTER TABLE command : %s", pszStatement);
7538 0 : CSLDestroy(papszTokens);
7539 0 : return nullptr;
7540 : }
7541 : }
7542 :
7543 : /* -------------------------------------------------------------------- */
7544 : /* Preparse the SQL statement. */
7545 : /* -------------------------------------------------------------------- */
7546 2850 : swq_select *psSelectInfo = new swq_select();
7547 2850 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7548 2850 : if (poSelectParseOptions != nullptr)
7549 8 : poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7550 2850 : if (psSelectInfo->preparse(pszStatement,
7551 2850 : poCustomFuncRegistrar != nullptr) != CE_None)
7552 : {
7553 181 : delete psSelectInfo;
7554 181 : return nullptr;
7555 : }
7556 :
7557 : /* -------------------------------------------------------------------- */
7558 : /* If there is no UNION ALL, build result layer. */
7559 : /* -------------------------------------------------------------------- */
7560 2669 : if (psSelectInfo->poOtherSelect == nullptr)
7561 : {
7562 2663 : return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7563 2663 : pszDialect, poSelectParseOptions);
7564 : }
7565 :
7566 : /* -------------------------------------------------------------------- */
7567 : /* Build result union layer. */
7568 : /* -------------------------------------------------------------------- */
7569 6 : int nSrcLayers = 0;
7570 6 : OGRLayer **papoSrcLayers = nullptr;
7571 :
7572 6 : do
7573 : {
7574 12 : swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7575 12 : psSelectInfo->poOtherSelect = nullptr;
7576 :
7577 12 : OGRLayer *poLayer = BuildLayerFromSelectInfo(
7578 : psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7579 12 : if (poLayer == nullptr)
7580 : {
7581 : // Each source layer owns an independent select info.
7582 0 : for (int i = 0; i < nSrcLayers; ++i)
7583 0 : delete papoSrcLayers[i];
7584 0 : CPLFree(papoSrcLayers);
7585 :
7586 : // So we just have to destroy the remaining select info.
7587 0 : delete psNextSelectInfo;
7588 :
7589 0 : return nullptr;
7590 : }
7591 : else
7592 : {
7593 24 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7594 12 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7595 12 : papoSrcLayers[nSrcLayers] = poLayer;
7596 12 : ++nSrcLayers;
7597 :
7598 12 : psSelectInfo = psNextSelectInfo;
7599 : }
7600 12 : } while (psSelectInfo != nullptr);
7601 :
7602 6 : return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7603 : }
7604 :
7605 : //! @endcond
7606 :
7607 : /************************************************************************/
7608 : /* AbortSQL() */
7609 : /************************************************************************/
7610 :
7611 : /**
7612 : \brief Abort any SQL statement running in the data store.
7613 :
7614 : This function can be safely called from any thread (pending that the dataset
7615 : object is still alive). Driver implementations will make sure that it can be
7616 : called in a thread-safe way.
7617 :
7618 : This might not be implemented by all drivers. At time of writing, only SQLite,
7619 : GPKG and PG drivers implement it
7620 :
7621 : This method is the same as the C method GDALDatasetAbortSQL()
7622 :
7623 : @since GDAL 3.2.0
7624 :
7625 :
7626 : */
7627 :
7628 0 : OGRErr GDALDataset::AbortSQL()
7629 : {
7630 0 : CPLError(CE_Failure, CPLE_NotSupported,
7631 : "AbortSQL is not supported for this driver.");
7632 0 : return OGRERR_UNSUPPORTED_OPERATION;
7633 : }
7634 :
7635 : /************************************************************************/
7636 : /* BuildLayerFromSelectInfo() */
7637 : /************************************************************************/
7638 :
7639 : struct GDALSQLParseInfo
7640 : {
7641 : swq_field_list sFieldList;
7642 : int nExtraDSCount;
7643 : GDALDataset **papoExtraDS;
7644 : char *pszWHERE;
7645 : };
7646 :
7647 2675 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7648 : swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7649 : const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7650 : {
7651 5350 : std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7652 :
7653 2675 : std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7654 : GDALSQLParseInfo *psParseInfo =
7655 2675 : BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7656 :
7657 2675 : if (psParseInfo)
7658 : {
7659 2640 : const auto nErrorCounter = CPLGetErrorCounter();
7660 5280 : poResults = std::make_unique<OGRGenSQLResultsLayer>(
7661 2640 : this, std::move(psSelectInfoUnique), poSpatialFilter,
7662 5280 : psParseInfo->pszWHERE, pszDialect);
7663 2737 : if (CPLGetErrorCounter() > nErrorCounter &&
7664 97 : CPLGetLastErrorType() != CE_None)
7665 97 : poResults.reset();
7666 : }
7667 :
7668 2675 : DestroyParseInfo(psParseInfo);
7669 :
7670 5350 : return poResults.release();
7671 : }
7672 :
7673 : /************************************************************************/
7674 : /* DestroyParseInfo() */
7675 : /************************************************************************/
7676 :
7677 : //! @cond Doxygen_Suppress
7678 2744 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7679 : {
7680 2744 : if (psParseInfo == nullptr)
7681 35 : return;
7682 :
7683 2709 : CPLFree(psParseInfo->sFieldList.names);
7684 2709 : CPLFree(psParseInfo->sFieldList.types);
7685 2709 : CPLFree(psParseInfo->sFieldList.table_ids);
7686 2709 : CPLFree(psParseInfo->sFieldList.ids);
7687 :
7688 : // Release the datasets we have opened with OGROpenShared()
7689 : // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7690 : // has taken a reference on them, which it will release in its
7691 : // destructor.
7692 2716 : for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7693 7 : GDALClose(psParseInfo->papoExtraDS[iEDS]);
7694 :
7695 2709 : CPLFree(psParseInfo->papoExtraDS);
7696 2709 : CPLFree(psParseInfo->pszWHERE);
7697 2709 : CPLFree(psParseInfo);
7698 : }
7699 :
7700 : /************************************************************************/
7701 : /* BuildParseInfo() */
7702 : /************************************************************************/
7703 :
7704 : GDALSQLParseInfo *
7705 2709 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7706 : swq_select_parse_options *poSelectParseOptions)
7707 : {
7708 2709 : int nFirstLayerFirstSpecialFieldIndex = 0;
7709 :
7710 : GDALSQLParseInfo *psParseInfo =
7711 2709 : static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7712 :
7713 : /* -------------------------------------------------------------------- */
7714 : /* Validate that all the source tables are recognized, count */
7715 : /* fields. */
7716 : /* -------------------------------------------------------------------- */
7717 2709 : int nFieldCount = 0;
7718 :
7719 5486 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7720 : {
7721 2780 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7722 2780 : GDALDataset *poTableDS = this;
7723 :
7724 2780 : if (psTableDef->data_source != nullptr)
7725 : {
7726 7 : poTableDS = GDALDataset::FromHandle(
7727 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7728 7 : if (poTableDS == nullptr)
7729 : {
7730 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
7731 0 : CPLError(CE_Failure, CPLE_AppDefined,
7732 : "Unable to open secondary datasource "
7733 : "`%s' required by JOIN.",
7734 : psTableDef->data_source);
7735 :
7736 0 : DestroyParseInfo(psParseInfo);
7737 0 : return nullptr;
7738 : }
7739 :
7740 : // Keep in an array to release at the end of this function.
7741 14 : psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7742 7 : psParseInfo->papoExtraDS,
7743 7 : sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7744 7 : psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7745 : }
7746 :
7747 : OGRLayer *poSrcLayer =
7748 2780 : poTableDS->GetLayerByName(psTableDef->table_name);
7749 :
7750 2780 : if (poSrcLayer == nullptr)
7751 : {
7752 3 : CPLError(CE_Failure, CPLE_AppDefined,
7753 : "SELECT from table %s failed, no such table/featureclass.",
7754 : psTableDef->table_name);
7755 :
7756 3 : DestroyParseInfo(psParseInfo);
7757 3 : return nullptr;
7758 : }
7759 :
7760 2777 : nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7761 2777 : if (iTable == 0 ||
7762 34 : (poSelectParseOptions &&
7763 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7764 2740 : nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7765 :
7766 2777 : const char *pszFID = poSrcLayer->GetFIDColumn();
7767 3388 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7768 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7769 561 : nFieldCount++;
7770 : }
7771 :
7772 : /* -------------------------------------------------------------------- */
7773 : /* Build the field list for all indicated tables. */
7774 : /* -------------------------------------------------------------------- */
7775 :
7776 2706 : psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7777 2706 : psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7778 :
7779 2706 : psParseInfo->sFieldList.count = 0;
7780 2706 : psParseInfo->sFieldList.names = static_cast<char **>(
7781 2706 : CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7782 5412 : psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7783 2706 : sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7784 2706 : psParseInfo->sFieldList.table_ids = static_cast<int *>(
7785 2706 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7786 2706 : psParseInfo->sFieldList.ids = static_cast<int *>(
7787 2706 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7788 :
7789 2706 : bool bIsFID64 = false;
7790 5483 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7791 : {
7792 2777 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7793 2777 : GDALDataset *poTableDS = this;
7794 :
7795 2777 : if (psTableDef->data_source != nullptr)
7796 : {
7797 7 : poTableDS = GDALDataset::FromHandle(
7798 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7799 7 : CPLAssert(poTableDS != nullptr);
7800 7 : poTableDS->Dereference();
7801 : }
7802 :
7803 : OGRLayer *poSrcLayer =
7804 2777 : poTableDS->GetLayerByName(psTableDef->table_name);
7805 :
7806 2777 : for (int iField = 0;
7807 21263 : iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7808 : {
7809 : OGRFieldDefn *poFDefn =
7810 18486 : poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7811 18486 : const int iOutField = psParseInfo->sFieldList.count++;
7812 36972 : psParseInfo->sFieldList.names[iOutField] =
7813 18486 : const_cast<char *>(poFDefn->GetNameRef());
7814 18486 : if (poFDefn->GetType() == OFTInteger)
7815 : {
7816 5159 : if (poFDefn->GetSubType() == OFSTBoolean)
7817 160 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7818 : else
7819 4999 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7820 : }
7821 13327 : else if (poFDefn->GetType() == OFTInteger64)
7822 : {
7823 807 : if (poFDefn->GetSubType() == OFSTBoolean)
7824 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7825 : else
7826 807 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7827 : }
7828 12520 : else if (poFDefn->GetType() == OFTReal)
7829 2785 : psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7830 9735 : else if (poFDefn->GetType() == OFTString)
7831 6483 : psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7832 3252 : else if (poFDefn->GetType() == OFTTime)
7833 93 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7834 3159 : else if (poFDefn->GetType() == OFTDate)
7835 161 : psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7836 2998 : else if (poFDefn->GetType() == OFTDateTime)
7837 939 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7838 : else
7839 2059 : psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7840 :
7841 18486 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7842 18486 : psParseInfo->sFieldList.ids[iOutField] = iField;
7843 : }
7844 :
7845 2777 : if (iTable == 0)
7846 : {
7847 2706 : nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7848 : }
7849 :
7850 2777 : if (iTable == 0 ||
7851 34 : (poSelectParseOptions &&
7852 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7853 : {
7854 :
7855 2740 : for (int iField = 0;
7856 5039 : iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7857 : iField++)
7858 : {
7859 : OGRGeomFieldDefn *poFDefn =
7860 2299 : poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7861 2299 : const int iOutField = psParseInfo->sFieldList.count++;
7862 4598 : psParseInfo->sFieldList.names[iOutField] =
7863 2299 : const_cast<char *>(poFDefn->GetNameRef());
7864 2299 : if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7865 1464 : psParseInfo->sFieldList.names[iOutField] =
7866 : const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7867 2299 : psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7868 :
7869 2299 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7870 2299 : psParseInfo->sFieldList.ids[iOutField] =
7871 2299 : GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7872 : poSrcLayer->GetLayerDefn(), iField);
7873 : }
7874 : }
7875 :
7876 2778 : if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7877 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7878 : {
7879 1 : bIsFID64 = true;
7880 : }
7881 : }
7882 :
7883 : /* -------------------------------------------------------------------- */
7884 : /* Expand '*' in 'SELECT *' now before we add the pseudo fields */
7885 : /* -------------------------------------------------------------------- */
7886 2706 : const bool bAlwaysPrefixWithTableName =
7887 2748 : poSelectParseOptions &&
7888 42 : poSelectParseOptions->bAlwaysPrefixWithTableName;
7889 2706 : if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7890 2706 : bAlwaysPrefixWithTableName) != CE_None)
7891 : {
7892 2 : DestroyParseInfo(psParseInfo);
7893 2 : return nullptr;
7894 : }
7895 :
7896 16224 : for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7897 : {
7898 13520 : psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7899 13520 : const_cast<char *>(SpecialFieldNames[iField]);
7900 13520 : psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7901 13520 : (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7902 : : SpecialFieldTypes[iField];
7903 13520 : psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7904 13520 : psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7905 13520 : nFirstLayerFirstSpecialFieldIndex + iField;
7906 13520 : psParseInfo->sFieldList.count++;
7907 : }
7908 :
7909 : /* In the case a layer has an explicit FID column name, then add it */
7910 : /* so it can be selected */
7911 5479 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7912 : {
7913 2775 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7914 2775 : GDALDataset *poTableDS = this;
7915 :
7916 2775 : if (psTableDef->data_source != nullptr)
7917 : {
7918 7 : poTableDS = GDALDataset::FromHandle(
7919 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7920 7 : CPLAssert(poTableDS != nullptr);
7921 7 : poTableDS->Dereference();
7922 : }
7923 :
7924 : OGRLayer *poSrcLayer =
7925 2775 : poTableDS->GetLayerByName(psTableDef->table_name);
7926 :
7927 2775 : const char *pszFID = poSrcLayer->GetFIDColumn();
7928 3386 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7929 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7930 : {
7931 561 : const int iOutField = psParseInfo->sFieldList.count++;
7932 561 : psParseInfo->sFieldList.names[iOutField] =
7933 : const_cast<char *>(pszFID);
7934 561 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7935 0 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7936 : {
7937 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7938 : }
7939 : else
7940 : {
7941 561 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7942 : }
7943 561 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7944 1122 : psParseInfo->sFieldList.ids[iOutField] =
7945 561 : poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7946 : }
7947 : }
7948 :
7949 : /* -------------------------------------------------------------------- */
7950 : /* Finish the parse operation. */
7951 : /* -------------------------------------------------------------------- */
7952 2704 : if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7953 : CE_None)
7954 : {
7955 30 : DestroyParseInfo(psParseInfo);
7956 30 : return nullptr;
7957 : }
7958 :
7959 : /* -------------------------------------------------------------------- */
7960 : /* Extract the WHERE expression to use separately. */
7961 : /* -------------------------------------------------------------------- */
7962 2674 : if (psSelectInfo->where_expr != nullptr)
7963 : {
7964 1134 : psParseInfo->pszWHERE =
7965 1134 : psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7966 : // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7967 : }
7968 :
7969 2674 : return psParseInfo;
7970 : }
7971 :
7972 : //! @endcond
7973 :
7974 : /************************************************************************/
7975 : /* ReleaseResultSet() */
7976 : /************************************************************************/
7977 :
7978 : /**
7979 : \brief Release results of ExecuteSQL().
7980 :
7981 : This method should only be used to deallocate OGRLayers resulting from
7982 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
7983 : results set before destroying the GDALDataset may cause errors.
7984 :
7985 : This method is the same as the C function GDALDatasetReleaseResultSet() and the
7986 : deprecated OGR_DS_ReleaseResultSet().
7987 :
7988 : @param poResultsSet the result of a previous ExecuteSQL() call.
7989 : */
7990 :
7991 2589 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7992 :
7993 : {
7994 2589 : delete poResultsSet;
7995 2589 : }
7996 :
7997 : /************************************************************************/
7998 : /* GetStyleTable() */
7999 : /************************************************************************/
8000 :
8001 : /**
8002 : \brief Returns dataset style table.
8003 :
8004 : This method is the same as the C function GDALDatasetGetStyleTable() and the
8005 : deprecated OGR_DS_GetStyleTable().
8006 :
8007 : @return pointer to a style table which should not be modified or freed by the
8008 : caller.
8009 : */
8010 :
8011 1058 : OGRStyleTable *GDALDataset::GetStyleTable()
8012 : {
8013 1058 : return m_poStyleTable;
8014 : }
8015 :
8016 : /************************************************************************/
8017 : /* SetStyleTableDirectly() */
8018 : /************************************************************************/
8019 :
8020 : /**
8021 : \brief Set dataset style table.
8022 :
8023 : This method operate exactly as SetStyleTable() except that it
8024 : assumes ownership of the passed table.
8025 :
8026 : This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8027 : and the deprecated OGR_DS_SetStyleTableDirectly().
8028 :
8029 : @param poStyleTable pointer to style table to set
8030 :
8031 : */
8032 0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8033 : {
8034 0 : if (m_poStyleTable)
8035 0 : delete m_poStyleTable;
8036 0 : m_poStyleTable = poStyleTable;
8037 0 : }
8038 :
8039 : /************************************************************************/
8040 : /* SetStyleTable() */
8041 : /************************************************************************/
8042 :
8043 : /**
8044 : \brief Set dataset style table.
8045 :
8046 : This method operate exactly as SetStyleTableDirectly() except
8047 : that it does not assume ownership of the passed table.
8048 :
8049 : This method is the same as the C function GDALDatasetSetStyleTable() and the
8050 : deprecated OGR_DS_SetStyleTable().
8051 :
8052 : @param poStyleTable pointer to style table to set
8053 :
8054 : */
8055 :
8056 1054 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8057 : {
8058 1054 : if (m_poStyleTable)
8059 0 : delete m_poStyleTable;
8060 1054 : if (poStyleTable)
8061 1 : m_poStyleTable = poStyleTable->Clone();
8062 1054 : }
8063 :
8064 : /************************************************************************/
8065 : /* IsGenericSQLDialect() */
8066 : /************************************************************************/
8067 :
8068 : //! @cond Doxygen_Suppress
8069 1780 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8070 : {
8071 3252 : return pszDialect != nullptr &&
8072 3252 : (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8073 : }
8074 :
8075 : //! @endcond
8076 :
8077 : /************************************************************************/
8078 : /* GetLayerCount() */
8079 : /************************************************************************/
8080 :
8081 : /**
8082 : \brief Get the number of layers in this dataset.
8083 :
8084 : This method is the same as the C function GDALDatasetGetLayerCount(),
8085 : and the deprecated OGR_DS_GetLayerCount().
8086 :
8087 : Note that even if this method is const, there is no guarantee it can be
8088 : safely called by concurrent threads on the same GDALDataset object.
8089 :
8090 : @return layer count.
8091 : */
8092 :
8093 123642 : int GDALDataset::GetLayerCount() const
8094 : {
8095 123642 : return 0;
8096 : }
8097 :
8098 : /************************************************************************/
8099 : /* GetLayer() */
8100 : /************************************************************************/
8101 :
8102 : /**
8103 : \fn const GDALDataset::GetLayer(int) const
8104 : \brief Fetch a layer by index.
8105 :
8106 : The returned layer remains owned by the
8107 : GDALDataset and should not be deleted by the application.
8108 :
8109 : Note that even if this method is const, there is no guarantee it can be
8110 : safely called by concurrent threads on the same GDALDataset object.
8111 :
8112 : See GetLayers() for a C++ iterator version of this method.
8113 :
8114 : This method is the same as the C function GDALDatasetGetLayer() and the
8115 : deprecated OGR_DS_GetLayer().
8116 :
8117 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8118 :
8119 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8120 :
8121 : @see GetLayers()
8122 :
8123 : @since GDAL 3.12
8124 : */
8125 :
8126 0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8127 : {
8128 0 : return nullptr;
8129 : }
8130 :
8131 : /**
8132 : \fn GDALDataset::GetLayer(int)
8133 : \brief Fetch a layer by index.
8134 :
8135 : The returned layer remains owned by the
8136 : GDALDataset and should not be deleted by the application.
8137 :
8138 : See GetLayers() for a C++ iterator version of this method.
8139 :
8140 : This method is the same as the C function GDALDatasetGetLayer() and the
8141 : deprecated OGR_DS_GetLayer().
8142 :
8143 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8144 :
8145 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8146 :
8147 : @see GetLayers()
8148 : */
8149 :
8150 : /************************************************************************/
8151 : /* IsLayerPrivate() */
8152 : /************************************************************************/
8153 :
8154 : /**
8155 : \fn GDALDataset::IsLayerPrivate(int)
8156 : \brief Returns true if the layer at the specified index is deemed a private or
8157 : system table, or an internal detail only.
8158 :
8159 : This method is the same as the C function GDALDatasetIsLayerPrivate().
8160 :
8161 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8162 :
8163 : @return true if the layer is a private or system table.
8164 :
8165 : @since GDAL 3.4
8166 : */
8167 :
8168 1070 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8169 : {
8170 1070 : return false;
8171 : }
8172 :
8173 : /************************************************************************/
8174 : /* ResetReading() */
8175 : /************************************************************************/
8176 :
8177 : /**
8178 : \brief Reset feature reading to start on the first feature.
8179 :
8180 : This affects GetNextFeature().
8181 :
8182 : Depending on drivers, this may also have the side effect of calling
8183 : OGRLayer::ResetReading() on the layers of this dataset.
8184 :
8185 : This method is the same as the C function GDALDatasetResetReading().
8186 :
8187 : */
8188 7 : void GDALDataset::ResetReading()
8189 : {
8190 7 : if (!m_poPrivate)
8191 0 : return;
8192 7 : m_poPrivate->nCurrentLayerIdx = 0;
8193 7 : m_poPrivate->nLayerCount = -1;
8194 7 : m_poPrivate->poCurrentLayer = nullptr;
8195 7 : m_poPrivate->nFeatureReadInLayer = 0;
8196 7 : m_poPrivate->nFeatureReadInDataset = 0;
8197 7 : m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8198 7 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8199 : }
8200 :
8201 : /************************************************************************/
8202 : /* GDALDatasetResetReading() */
8203 : /************************************************************************/
8204 :
8205 : /**
8206 : \brief Reset feature reading to start on the first feature.
8207 :
8208 : This affects GDALDatasetGetNextFeature().
8209 :
8210 : Depending on drivers, this may also have the side effect of calling
8211 : OGR_L_ResetReading() on the layers of this dataset.
8212 :
8213 : This method is the same as the C++ method GDALDataset::ResetReading()
8214 :
8215 : @param hDS dataset handle
8216 : */
8217 14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8218 : {
8219 14 : VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8220 :
8221 14 : return GDALDataset::FromHandle(hDS)->ResetReading();
8222 : }
8223 :
8224 : /************************************************************************/
8225 : /* GetNextFeature() */
8226 : /************************************************************************/
8227 :
8228 : /**
8229 : \brief Fetch the next available feature from this dataset.
8230 :
8231 : This method is intended for the few drivers where OGRLayer::GetNextFeature()
8232 : is not efficient, but in general OGRLayer::GetNextFeature() is a more
8233 : natural API.
8234 :
8235 : See GetFeatures() for a C++ iterator version of this method.
8236 :
8237 : The returned feature becomes the responsibility of the caller to
8238 : delete with OGRFeature::DestroyFeature().
8239 :
8240 : Depending on the driver, this method may return features from layers in a
8241 : non sequential way. This is what may happen when the
8242 : ODsCRandomLayerRead capability is declared (for example for the
8243 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8244 : advised to use GDALDataset::GetNextFeature() instead of
8245 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8246 : implementation.
8247 :
8248 : The default implementation, used by most drivers, will
8249 : however iterate over each layer, and then over each feature within this
8250 : layer.
8251 :
8252 : This method takes into account spatial and attribute filters set on layers that
8253 : will be iterated upon.
8254 :
8255 : The ResetReading() method can be used to start at the beginning again.
8256 :
8257 : Depending on drivers, this may also have the side effect of calling
8258 : OGRLayer::GetNextFeature() on the layers of this dataset.
8259 :
8260 : This method is the same as the C function GDALDatasetGetNextFeature().
8261 :
8262 : @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8263 : layer to which the object belongs to, or NULL.
8264 : It is possible that the output of *ppoBelongingLayer
8265 : to be NULL despite the feature not being NULL.
8266 : @param pdfProgressPct a pointer to a double variable to receive the
8267 : percentage progress (in [0,1] range), or NULL.
8268 : On return, the pointed value might be negative if
8269 : determining the progress is not possible.
8270 : @param pfnProgress a progress callback to report progress (for
8271 : GetNextFeature() calls that might have a long
8272 : duration) and offer cancellation possibility, or NULL.
8273 : @param pProgressData user data provided to pfnProgress, or NULL
8274 : @return a feature, or NULL if no more features are available.
8275 : @see GetFeatures()
8276 : */
8277 :
8278 68 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8279 : double *pdfProgressPct,
8280 : GDALProgressFunc pfnProgress,
8281 : void *pProgressData)
8282 : {
8283 68 : if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8284 : {
8285 2 : if (ppoBelongingLayer != nullptr)
8286 2 : *ppoBelongingLayer = nullptr;
8287 2 : if (pdfProgressPct != nullptr)
8288 1 : *pdfProgressPct = 1.0;
8289 2 : if (pfnProgress != nullptr)
8290 0 : pfnProgress(1.0, "", pProgressData);
8291 2 : return nullptr;
8292 : }
8293 :
8294 66 : if (m_poPrivate->poCurrentLayer == nullptr &&
8295 11 : (pdfProgressPct != nullptr || pfnProgress != nullptr))
8296 : {
8297 4 : if (m_poPrivate->nLayerCount < 0)
8298 : {
8299 4 : m_poPrivate->nLayerCount = GetLayerCount();
8300 : }
8301 :
8302 4 : if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8303 : {
8304 4 : m_poPrivate->nTotalFeatures = 0;
8305 8 : for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8306 : {
8307 7 : OGRLayer *poLayer = GetLayer(i);
8308 14 : if (poLayer == nullptr ||
8309 7 : !poLayer->TestCapability(OLCFastFeatureCount))
8310 : {
8311 3 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8312 3 : break;
8313 : }
8314 4 : GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8315 4 : if (nCount < 0)
8316 : {
8317 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8318 0 : break;
8319 : }
8320 4 : m_poPrivate->nTotalFeatures += nCount;
8321 : }
8322 : }
8323 : }
8324 :
8325 : while (true)
8326 : {
8327 82 : if (m_poPrivate->poCurrentLayer == nullptr)
8328 : {
8329 56 : m_poPrivate->poCurrentLayer =
8330 28 : GetLayer(m_poPrivate->nCurrentLayerIdx);
8331 28 : if (m_poPrivate->poCurrentLayer == nullptr)
8332 : {
8333 10 : m_poPrivate->nCurrentLayerIdx = -1;
8334 10 : if (ppoBelongingLayer != nullptr)
8335 7 : *ppoBelongingLayer = nullptr;
8336 10 : if (pdfProgressPct != nullptr)
8337 1 : *pdfProgressPct = 1.0;
8338 10 : return nullptr;
8339 : }
8340 18 : m_poPrivate->poCurrentLayer->ResetReading();
8341 18 : m_poPrivate->nFeatureReadInLayer = 0;
8342 18 : if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8343 : {
8344 0 : if (m_poPrivate->poCurrentLayer->TestCapability(
8345 0 : OLCFastFeatureCount))
8346 0 : m_poPrivate->nTotalFeaturesInLayer =
8347 0 : m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8348 : else
8349 0 : m_poPrivate->nTotalFeaturesInLayer = 0;
8350 : }
8351 : }
8352 72 : OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8353 72 : if (poFeature == nullptr)
8354 : {
8355 16 : m_poPrivate->nCurrentLayerIdx++;
8356 16 : m_poPrivate->poCurrentLayer = nullptr;
8357 16 : continue;
8358 : }
8359 :
8360 56 : m_poPrivate->nFeatureReadInLayer++;
8361 56 : m_poPrivate->nFeatureReadInDataset++;
8362 56 : if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8363 : {
8364 9 : double dfPct = 0.0;
8365 9 : if (m_poPrivate->nTotalFeatures > 0)
8366 : {
8367 4 : dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8368 4 : m_poPrivate->nTotalFeatures;
8369 : }
8370 : else
8371 : {
8372 5 : dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8373 5 : m_poPrivate->nLayerCount;
8374 5 : if (m_poPrivate->nTotalFeaturesInLayer > 0)
8375 : {
8376 0 : dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8377 0 : m_poPrivate->nTotalFeaturesInLayer /
8378 0 : m_poPrivate->nLayerCount;
8379 : }
8380 : }
8381 9 : if (pdfProgressPct)
8382 4 : *pdfProgressPct = dfPct;
8383 9 : if (pfnProgress)
8384 5 : pfnProgress(dfPct, "", nullptr);
8385 : }
8386 :
8387 56 : if (ppoBelongingLayer != nullptr)
8388 51 : *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8389 56 : return poFeature;
8390 16 : }
8391 : }
8392 :
8393 : /************************************************************************/
8394 : /* GDALDatasetGetNextFeature() */
8395 : /************************************************************************/
8396 : /**
8397 : \brief Fetch the next available feature from this dataset.
8398 :
8399 : This method is intended for the few drivers where OGR_L_GetNextFeature()
8400 : is not efficient, but in general OGR_L_GetNextFeature() is a more
8401 : natural API.
8402 :
8403 : The returned feature becomes the responsibility of the caller to
8404 : delete with OGRFeature::DestroyFeature().
8405 :
8406 : Depending on the driver, this method may return features from layers in a
8407 : non sequential way. This is what may happen when the
8408 : ODsCRandomLayerRead capability is declared (for example for the
8409 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8410 : advised to use GDALDataset::GetNextFeature() instead of
8411 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8412 : implementation.
8413 :
8414 : The default implementation, used by most drivers, will
8415 : however iterate over each layer, and then over each feature within this
8416 : layer.
8417 :
8418 : This method takes into account spatial and attribute filters set on layers that
8419 : will be iterated upon.
8420 :
8421 : The ResetReading() method can be used to start at the beginning again.
8422 :
8423 : Depending on drivers, this may also have the side effect of calling
8424 : OGRLayer::GetNextFeature() on the layers of this dataset.
8425 :
8426 : This method is the same as the C++ method GDALDataset::GetNextFeature()
8427 :
8428 : @param hDS dataset handle.
8429 : @param phBelongingLayer a pointer to a OGRLayer* variable to receive the
8430 : layer to which the object belongs to, or NULL.
8431 : It is possible that the output of *ppoBelongingLayer
8432 : to be NULL despite the feature not being NULL.
8433 : @param pdfProgressPct a pointer to a double variable to receive the
8434 : percentage progress (in [0,1] range), or NULL.
8435 : On return, the pointed value might be negative if
8436 : determining the progress is not possible.
8437 : @param pfnProgress a progress callback to report progress (for
8438 : GetNextFeature() calls that might have a long
8439 : duration) and offer cancellation possibility, or NULL
8440 : @param pProgressData user data provided to pfnProgress, or NULL
8441 : @return a feature, or NULL if no more features are available.
8442 : */
8443 1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8444 : OGRLayerH *phBelongingLayer,
8445 : double *pdfProgressPct,
8446 : GDALProgressFunc pfnProgress,
8447 : void *pProgressData)
8448 : {
8449 1917 : VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8450 :
8451 3834 : return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8452 : reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8453 3834 : pfnProgress, pProgressData));
8454 : }
8455 :
8456 : /************************************************************************/
8457 : /* TestCapability() */
8458 : /************************************************************************/
8459 :
8460 : /**
8461 : \fn GDALDataset::TestCapability( const char * pszCap )
8462 : \brief Test if capability is available.
8463 :
8464 : One of the following dataset capability names can be passed into this
8465 : method, and a TRUE or FALSE value will be returned indicating whether or not
8466 : the capability is available for this object.
8467 :
8468 : <ul>
8469 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8470 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8471 : layers.<p>
8472 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8473 : datasource support CreateGeomField() just after layer creation.<p>
8474 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8475 : geometries.<p>
8476 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8477 : transactions.<p>
8478 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8479 : transactions through emulation.<p>
8480 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8481 : GetNextFeature() implementation, potentially returning features from
8482 : layers in a non sequential way.<p>
8483 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8484 : CreateFeature() on layers in a non sequential way.<p>
8485 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8486 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8487 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8488 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8489 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8490 : </ul>
8491 :
8492 : The \#define macro forms of the capability names should be used in preference
8493 : to the strings themselves to avoid misspelling.
8494 :
8495 : This method is the same as the C function GDALDatasetTestCapability() and the
8496 : deprecated OGR_DS_TestCapability().
8497 :
8498 : @param pszCap the capability to test.
8499 :
8500 : @return TRUE if capability available otherwise FALSE.
8501 : */
8502 :
8503 1092 : int GDALDataset::TestCapability(const char *pszCap) const
8504 : {
8505 1092 : if (EQUAL(pszCap, GDsCFastGetExtent) ||
8506 1090 : EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8507 : {
8508 4 : for (auto &&poLayer : GetLayers())
8509 : {
8510 2 : if (!poLayer->TestCapability(OLCFastGetExtent))
8511 2 : return FALSE;
8512 : }
8513 2 : return TRUE;
8514 : }
8515 1088 : return FALSE;
8516 : }
8517 :
8518 : /************************************************************************/
8519 : /* GDALDatasetTestCapability() */
8520 : /************************************************************************/
8521 :
8522 : /**
8523 : \brief Test if capability is available.
8524 :
8525 : One of the following dataset capability names can be passed into this
8526 : function, and a TRUE or FALSE value will be returned indicating whether or not
8527 : the capability is available for this object.
8528 :
8529 : <ul>
8530 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8531 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8532 : layers.<p>
8533 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8534 : datasource support CreateGeomField() just after layer creation.<p>
8535 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8536 : geometries.<p>
8537 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8538 : transactions.<p>
8539 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8540 : transactions through emulation.<p>
8541 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8542 : GetNextFeature() implementation, potentially returning features from
8543 : layers in a non sequential way.<p>
8544 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8545 : CreateFeature() on layers in a non sequential way.<p>
8546 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8547 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8548 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8549 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8550 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8551 : </ul>
8552 :
8553 : The \#define macro forms of the capability names should be used in preference
8554 : to the strings themselves to avoid misspelling.
8555 :
8556 : This function is the same as the C++ method GDALDataset::TestCapability()
8557 :
8558 :
8559 : @param hDS the dataset handle.
8560 : @param pszCap the capability to test.
8561 :
8562 : @return TRUE if capability available otherwise FALSE.
8563 : */
8564 132 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8565 :
8566 : {
8567 132 : VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8568 132 : VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8569 :
8570 132 : return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8571 : }
8572 :
8573 : /************************************************************************/
8574 : /* StartTransaction() */
8575 : /************************************************************************/
8576 :
8577 : /**
8578 : \fn GDALDataset::StartTransaction(int)
8579 : \brief For datasources which support transactions, StartTransaction creates a
8580 : `transaction.
8581 :
8582 : If starting the transaction fails, will return
8583 : OGRERR_FAILURE. Datasources which do not support transactions will
8584 : always return OGRERR_UNSUPPORTED_OPERATION.
8585 :
8586 : Nested transactions are not supported.
8587 :
8588 : All changes done after the start of the transaction are definitely applied in
8589 : the datasource if CommitTransaction() is called. They may be canceled by
8590 : calling RollbackTransaction() instead.
8591 :
8592 : At the time of writing, transactions only apply on vector layers.
8593 :
8594 : Datasets that support transactions will advertise the ODsCTransactions
8595 : capability. Use of transactions at dataset level is generally preferred to
8596 : transactions at layer level, whose scope is rarely limited to the layer from
8597 : which it was started.
8598 :
8599 : In case StartTransaction() fails, neither CommitTransaction() or
8600 : RollbackTransaction() should be called.
8601 :
8602 : If an error occurs after a successful StartTransaction(), the whole transaction
8603 : may or may not be implicitly canceled, depending on drivers. (e.g. the PG
8604 : driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8605 : an explicit call to RollbackTransaction() should be done to keep things
8606 : balanced.
8607 :
8608 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8609 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8610 : with significant overhead, in which case the user must explicitly allow for
8611 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8612 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8613 : ODsCTransactions).
8614 :
8615 : This function is the same as the C function GDALDatasetStartTransaction().
8616 :
8617 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8618 : transaction
8619 : mechanism is acceptable.
8620 :
8621 : @return OGRERR_NONE on success.
8622 : */
8623 :
8624 43 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8625 : {
8626 43 : return OGRERR_UNSUPPORTED_OPERATION;
8627 : }
8628 :
8629 : /************************************************************************/
8630 : /* GDALDatasetStartTransaction() */
8631 : /************************************************************************/
8632 :
8633 : /**
8634 : \brief For datasources which support transactions, StartTransaction creates a
8635 : transaction.
8636 :
8637 : If starting the transaction fails, will return
8638 : OGRERR_FAILURE. Datasources which do not support transactions will
8639 : always return OGRERR_UNSUPPORTED_OPERATION.
8640 :
8641 : Nested transactions are not supported.
8642 :
8643 : All changes done after the start of the transaction are definitely applied in
8644 : the datasource if CommitTransaction() is called. They may be canceled by
8645 : calling RollbackTransaction() instead.
8646 :
8647 : At the time of writing, transactions only apply on vector layers.
8648 :
8649 : Datasets that support transactions will advertise the ODsCTransactions
8650 : capability.
8651 : Use of transactions at dataset level is generally preferred to transactions at
8652 : layer level, whose scope is rarely limited to the layer from which it was
8653 : started.
8654 :
8655 : In case StartTransaction() fails, neither CommitTransaction() or
8656 : RollbackTransaction() should be called.
8657 :
8658 : If an error occurs after a successful StartTransaction(), the whole
8659 : transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8660 : the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8661 : error, an explicit call to RollbackTransaction() should be done to keep things
8662 : balanced.
8663 :
8664 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8665 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8666 : with significant overhead, in which case the user must explicitly allow for
8667 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8668 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8669 : ODsCTransactions).
8670 :
8671 : This function is the same as the C++ method GDALDataset::StartTransaction()
8672 :
8673 : @param hDS the dataset handle.
8674 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8675 : transaction
8676 : mechanism is acceptable.
8677 :
8678 : @return OGRERR_NONE on success.
8679 : */
8680 106 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8681 : {
8682 106 : VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8683 : OGRERR_INVALID_HANDLE);
8684 :
8685 : #ifdef OGRAPISPY_ENABLED
8686 106 : if (bOGRAPISpyEnabled)
8687 2 : OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8688 : #endif
8689 :
8690 106 : return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8691 : }
8692 :
8693 : /************************************************************************/
8694 : /* CommitTransaction() */
8695 : /************************************************************************/
8696 :
8697 : /**
8698 : \brief For datasources which support transactions, CommitTransaction commits a
8699 : transaction.
8700 :
8701 : If no transaction is active, or the commit fails, will return
8702 : OGRERR_FAILURE. Datasources which do not support transactions will
8703 : always return OGRERR_UNSUPPORTED_OPERATION.
8704 :
8705 : Depending on drivers, this may or may not abort layer sequential readings that
8706 : are active.
8707 :
8708 : This function is the same as the C function GDALDatasetCommitTransaction().
8709 :
8710 : @return OGRERR_NONE on success.
8711 : */
8712 58 : OGRErr GDALDataset::CommitTransaction()
8713 : {
8714 58 : return OGRERR_UNSUPPORTED_OPERATION;
8715 : }
8716 :
8717 : /************************************************************************/
8718 : /* GDALDatasetCommitTransaction() */
8719 : /************************************************************************/
8720 :
8721 : /**
8722 : \brief For datasources which support transactions, CommitTransaction commits a
8723 : transaction.
8724 :
8725 : If no transaction is active, or the commit fails, will return
8726 : OGRERR_FAILURE. Datasources which do not support transactions will
8727 : always return OGRERR_UNSUPPORTED_OPERATION.
8728 :
8729 : Depending on drivers, this may or may not abort layer sequential readings that
8730 : are active.
8731 :
8732 : This function is the same as the C++ method GDALDataset::CommitTransaction()
8733 :
8734 : @return OGRERR_NONE on success.
8735 : */
8736 77 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8737 : {
8738 77 : VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8739 : OGRERR_INVALID_HANDLE);
8740 :
8741 : #ifdef OGRAPISPY_ENABLED
8742 77 : if (bOGRAPISpyEnabled)
8743 2 : OGRAPISpy_Dataset_CommitTransaction(hDS);
8744 : #endif
8745 :
8746 77 : return GDALDataset::FromHandle(hDS)->CommitTransaction();
8747 : }
8748 :
8749 : /************************************************************************/
8750 : /* RollbackTransaction() */
8751 : /************************************************************************/
8752 :
8753 : /**
8754 : \brief For datasources which support transactions, RollbackTransaction will
8755 : roll back a datasource to its state before the start of the current
8756 : transaction.
8757 : If no transaction is active, or the rollback fails, will return
8758 : OGRERR_FAILURE. Datasources which do not support transactions will
8759 : always return OGRERR_UNSUPPORTED_OPERATION.
8760 :
8761 : This function is the same as the C function GDALDatasetRollbackTransaction().
8762 :
8763 : @return OGRERR_NONE on success.
8764 : */
8765 2 : OGRErr GDALDataset::RollbackTransaction()
8766 : {
8767 2 : return OGRERR_UNSUPPORTED_OPERATION;
8768 : }
8769 :
8770 : /************************************************************************/
8771 : /* GDALDatasetRollbackTransaction() */
8772 : /************************************************************************/
8773 :
8774 : /**
8775 : \brief For datasources which support transactions, RollbackTransaction will
8776 : roll back a datasource to its state before the start of the current
8777 : transaction.
8778 : If no transaction is active, or the rollback fails, will return
8779 : OGRERR_FAILURE. Datasources which do not support transactions will
8780 : always return OGRERR_UNSUPPORTED_OPERATION.
8781 :
8782 : This function is the same as the C++ method GDALDataset::RollbackTransaction().
8783 :
8784 : @return OGRERR_NONE on success.
8785 : */
8786 44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8787 : {
8788 44 : VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8789 : OGRERR_INVALID_HANDLE);
8790 :
8791 : #ifdef OGRAPISPY_ENABLED
8792 44 : if (bOGRAPISpyEnabled)
8793 2 : OGRAPISpy_Dataset_RollbackTransaction(hDS);
8794 : #endif
8795 :
8796 44 : return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8797 : }
8798 :
8799 : //! @cond Doxygen_Suppress
8800 :
8801 : /************************************************************************/
8802 : /* ShareLockWithParentDataset() */
8803 : /************************************************************************/
8804 :
8805 : /* To be used typically by the GTiff driver to link overview datasets */
8806 : /* with their main dataset, so that they share the same lock */
8807 : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
8808 : /* The parent dataset should remain alive while the this dataset is alive */
8809 :
8810 2571 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8811 : {
8812 2571 : if (m_poPrivate != nullptr)
8813 : {
8814 2571 : m_poPrivate->poParentDataset = poParentDataset;
8815 : }
8816 2571 : }
8817 :
8818 : /************************************************************************/
8819 : /* SetQueryLoggerFunc() */
8820 : /************************************************************************/
8821 :
8822 0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8823 : CPL_UNUSED void *context)
8824 : {
8825 0 : return false;
8826 : }
8827 :
8828 : /************************************************************************/
8829 : /* EnterReadWrite() */
8830 : /************************************************************************/
8831 :
8832 8322680 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8833 : {
8834 16645400 : if (m_poPrivate == nullptr ||
8835 8322680 : IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8836 11992 : return FALSE;
8837 :
8838 8310690 : if (m_poPrivate->poParentDataset)
8839 242806 : return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8840 :
8841 8067890 : if (eAccess == GA_Update)
8842 : {
8843 2452730 : if (m_poPrivate->eStateReadWriteMutex ==
8844 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8845 : {
8846 : // In case dead-lock would occur, which is not impossible,
8847 : // this can be used to prevent it, but at the risk of other
8848 : // issues.
8849 11135 : if (CPLTestBool(
8850 : CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8851 : {
8852 11135 : m_poPrivate->eStateReadWriteMutex =
8853 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8854 : }
8855 : else
8856 : {
8857 0 : m_poPrivate->eStateReadWriteMutex =
8858 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8859 : }
8860 : }
8861 2452730 : if (m_poPrivate->eStateReadWriteMutex ==
8862 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8863 : {
8864 : // There should be no race related to creating this mutex since
8865 : // it should be first created through IWriteBlock() / IRasterIO()
8866 : // and then GDALRasterBlock might call it from another thread.
8867 : #ifdef DEBUG_VERBOSE
8868 : CPLDebug("GDAL",
8869 : "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8870 : CPLGetPID(), GetDescription());
8871 : #endif
8872 1566460 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8873 :
8874 : const int nCountMutex =
8875 1566460 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8876 1566460 : if (nCountMutex == 0 && eRWFlag == GF_Read)
8877 : {
8878 540061 : CPLReleaseMutex(m_poPrivate->hMutex);
8879 1726190 : for (int i = 0; i < nBands; i++)
8880 : {
8881 1186120 : auto blockCache = papoBands[i]->poBandBlockCache;
8882 1186120 : if (blockCache)
8883 824657 : blockCache->WaitCompletionPendingTasks();
8884 : }
8885 540061 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8886 : }
8887 :
8888 1566460 : return TRUE;
8889 : }
8890 : }
8891 6501420 : return FALSE;
8892 : }
8893 :
8894 : /************************************************************************/
8895 : /* LeaveReadWrite() */
8896 : /************************************************************************/
8897 :
8898 1795570 : void GDALDataset::LeaveReadWrite()
8899 : {
8900 1795570 : if (m_poPrivate)
8901 : {
8902 1795570 : if (m_poPrivate->poParentDataset)
8903 : {
8904 229107 : m_poPrivate->poParentDataset->LeaveReadWrite();
8905 229107 : return;
8906 : }
8907 :
8908 1566460 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8909 1566460 : CPLReleaseMutex(m_poPrivate->hMutex);
8910 : #ifdef DEBUG_VERBOSE
8911 : CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8912 : CPLGetPID(), GetDescription());
8913 : #endif
8914 : }
8915 : }
8916 :
8917 : /************************************************************************/
8918 : /* InitRWLock() */
8919 : /************************************************************************/
8920 :
8921 4009530 : void GDALDataset::InitRWLock()
8922 : {
8923 4009530 : if (m_poPrivate)
8924 : {
8925 4009530 : if (m_poPrivate->poParentDataset)
8926 : {
8927 8638 : m_poPrivate->poParentDataset->InitRWLock();
8928 8638 : return;
8929 : }
8930 :
8931 4000890 : if (m_poPrivate->eStateReadWriteMutex ==
8932 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8933 : {
8934 1 : if (EnterReadWrite(GF_Write))
8935 1 : LeaveReadWrite();
8936 : }
8937 : }
8938 : }
8939 :
8940 : /************************************************************************/
8941 : /* DisableReadWriteMutex() */
8942 : /************************************************************************/
8943 :
8944 : // The mutex logic is broken in multi-threaded situations, for example
8945 : // with 2 WarpedVRT datasets being read at the same time. In that
8946 : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8947 : // to disable it.
8948 36372 : void GDALDataset::DisableReadWriteMutex()
8949 : {
8950 36372 : if (m_poPrivate)
8951 : {
8952 36372 : if (m_poPrivate->poParentDataset)
8953 : {
8954 0 : m_poPrivate->poParentDataset->DisableReadWriteMutex();
8955 0 : return;
8956 : }
8957 :
8958 36372 : m_poPrivate->eStateReadWriteMutex =
8959 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8960 : }
8961 : }
8962 :
8963 : /************************************************************************/
8964 : /* TemporarilyDropReadWriteLock() */
8965 : /************************************************************************/
8966 :
8967 3441910 : void GDALDataset::TemporarilyDropReadWriteLock()
8968 : {
8969 3441910 : if (m_poPrivate == nullptr)
8970 0 : return;
8971 :
8972 3441910 : if (m_poPrivate->poParentDataset)
8973 : {
8974 26447 : m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8975 26447 : return;
8976 : }
8977 :
8978 : #ifndef __COVERITY__
8979 3415460 : if (m_poPrivate->hMutex)
8980 : {
8981 : #ifdef DEBUG_VERBOSE
8982 : CPLDebug("GDAL",
8983 : "[Thread " CPL_FRMT_GIB "] "
8984 : "Temporarily drop RW mutex for %s",
8985 : CPLGetPID(), GetDescription());
8986 : #endif
8987 425318 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8988 : const int nCount =
8989 425318 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8990 : #ifdef DEBUG_EXTRA
8991 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8992 : #endif
8993 1283680 : for (int i = 0; i < nCount + 1; i++)
8994 : {
8995 : // The mutex is recursive
8996 858365 : CPLReleaseMutex(m_poPrivate->hMutex);
8997 : }
8998 : }
8999 : #endif
9000 : }
9001 :
9002 : /************************************************************************/
9003 : /* ReacquireReadWriteLock() */
9004 : /************************************************************************/
9005 :
9006 3441910 : void GDALDataset::ReacquireReadWriteLock()
9007 : {
9008 3441910 : if (m_poPrivate == nullptr)
9009 0 : return;
9010 :
9011 3441910 : if (m_poPrivate->poParentDataset)
9012 : {
9013 26447 : m_poPrivate->poParentDataset->ReacquireReadWriteLock();
9014 26447 : return;
9015 : }
9016 :
9017 : #ifndef __COVERITY__
9018 3415460 : if (m_poPrivate->hMutex)
9019 : {
9020 : #ifdef DEBUG_VERBOSE
9021 : CPLDebug("GDAL",
9022 : "[Thread " CPL_FRMT_GIB "] "
9023 : "Reacquire temporarily dropped RW mutex for %s",
9024 : CPLGetPID(), GetDescription());
9025 : #endif
9026 425318 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9027 : const int nCount =
9028 425318 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9029 : #ifdef DEBUG_EXTRA
9030 : CPLAssert(nCount ==
9031 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9032 : #endif
9033 425318 : if (nCount == 0)
9034 18317 : CPLReleaseMutex(m_poPrivate->hMutex);
9035 451364 : for (int i = 0; i < nCount - 1; i++)
9036 : {
9037 : // The mutex is recursive
9038 26046 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9039 : }
9040 : }
9041 : #endif
9042 : }
9043 :
9044 : /************************************************************************/
9045 : /* AcquireMutex() */
9046 : /************************************************************************/
9047 :
9048 196 : int GDALDataset::AcquireMutex()
9049 : {
9050 196 : if (m_poPrivate == nullptr)
9051 0 : return 0;
9052 196 : if (m_poPrivate->poParentDataset)
9053 : {
9054 0 : return m_poPrivate->poParentDataset->AcquireMutex();
9055 : }
9056 :
9057 196 : return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9058 : }
9059 :
9060 : /************************************************************************/
9061 : /* ReleaseMutex() */
9062 : /************************************************************************/
9063 :
9064 196 : void GDALDataset::ReleaseMutex()
9065 : {
9066 196 : if (m_poPrivate)
9067 : {
9068 196 : if (m_poPrivate->poParentDataset)
9069 : {
9070 0 : m_poPrivate->poParentDataset->ReleaseMutex();
9071 0 : return;
9072 : }
9073 :
9074 196 : CPLReleaseMutex(m_poPrivate->hMutex);
9075 : }
9076 : }
9077 :
9078 : //! @endcond
9079 :
9080 : /************************************************************************/
9081 : /* GDALDataset::Features::Iterator::Private */
9082 : /************************************************************************/
9083 :
9084 : struct GDALDataset::Features::Iterator::Private
9085 : {
9086 : GDALDataset::FeatureLayerPair m_oPair{};
9087 : GDALDataset *m_poDS = nullptr;
9088 : bool m_bEOF = true;
9089 : };
9090 :
9091 4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9092 4 : : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9093 : {
9094 4 : m_poPrivate->m_poDS = poDS;
9095 4 : if (bStart)
9096 : {
9097 2 : poDS->ResetReading();
9098 4 : m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9099 2 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9100 2 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9101 : }
9102 4 : }
9103 :
9104 : GDALDataset::Features::Iterator::~Iterator() = default;
9105 :
9106 : const GDALDataset::FeatureLayerPair &
9107 20 : GDALDataset::Features::Iterator::operator*() const
9108 : {
9109 20 : return m_poPrivate->m_oPair;
9110 : }
9111 :
9112 20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9113 : {
9114 40 : m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9115 20 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9116 20 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9117 20 : return *this;
9118 : }
9119 :
9120 22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9121 : {
9122 22 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9123 : }
9124 :
9125 : /************************************************************************/
9126 : /* GetFeatures() */
9127 : /************************************************************************/
9128 :
9129 : /** Function that return an iterable object over features in the dataset
9130 : * layer.
9131 : *
9132 : * This is a C++ iterator friendly version of GetNextFeature().
9133 : *
9134 : * Using this iterator for standard range-based loops is safe, but
9135 : * due to implementation limitations, you shouldn't try to access
9136 : * (dereference) more than one iterator step at a time, since the
9137 : * FeatureLayerPair reference which is returned is reused.
9138 : *
9139 : * Typical use is:
9140 : * \code{.cpp}
9141 : * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9142 : * {
9143 : * std::cout << "Feature of layer " <<
9144 : * oFeatureLayerPair.layer->GetName() << std::endl;
9145 : * oFeatureLayerPair.feature->DumpReadable();
9146 : * }
9147 : * \endcode
9148 : *
9149 : * @see GetNextFeature()
9150 : *
9151 : */
9152 2 : GDALDataset::Features GDALDataset::GetFeatures()
9153 : {
9154 2 : return Features(this);
9155 : }
9156 :
9157 : /************************************************************************/
9158 : /* begin() */
9159 : /************************************************************************/
9160 :
9161 : /**
9162 : \brief Return beginning of feature iterator.
9163 :
9164 : */
9165 :
9166 2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9167 : {
9168 2 : return {m_poSelf, true};
9169 : }
9170 :
9171 : /************************************************************************/
9172 : /* end() */
9173 : /************************************************************************/
9174 :
9175 : /**
9176 : \brief Return end of feature iterator.
9177 :
9178 : */
9179 :
9180 2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9181 : {
9182 2 : return {m_poSelf, false};
9183 : }
9184 :
9185 : /************************************************************************/
9186 : /* GDALDataset::Layers::Iterator::Private */
9187 : /************************************************************************/
9188 :
9189 : struct GDALDataset::Layers::Iterator::Private
9190 : {
9191 : OGRLayer *m_poLayer = nullptr;
9192 : int m_iCurLayer = 0;
9193 : int m_nLayerCount = 0;
9194 : GDALDataset *m_poDS = nullptr;
9195 : };
9196 :
9197 2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9198 : {
9199 2 : }
9200 :
9201 : // False positive of cppcheck 1.72
9202 : // cppcheck-suppress uninitMemberVar
9203 9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9204 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9205 : {
9206 9 : }
9207 :
9208 5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9209 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9210 : {
9211 5 : }
9212 :
9213 110868 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9214 110868 : : m_poPrivate(new Private())
9215 : {
9216 110868 : m_poPrivate->m_poDS = poDS;
9217 110868 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9218 110868 : if (bStart)
9219 : {
9220 55436 : if (m_poPrivate->m_nLayerCount)
9221 46727 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9222 : }
9223 : else
9224 : {
9225 55432 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9226 : }
9227 110868 : }
9228 :
9229 : GDALDataset::Layers::Iterator::~Iterator() = default;
9230 :
9231 : // False positive of cppcheck 1.72
9232 : // cppcheck-suppress operatorEqVarError
9233 : GDALDataset::Layers::Iterator &
9234 1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9235 : {
9236 1 : *m_poPrivate = *oOther.m_poPrivate;
9237 1 : return *this;
9238 : }
9239 :
9240 3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9241 : GDALDataset::Layers::Iterator &&oOther) noexcept
9242 : {
9243 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9244 3 : return *this;
9245 : }
9246 :
9247 1800590 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9248 : {
9249 1800590 : return m_poPrivate->m_poLayer;
9250 : }
9251 :
9252 1786540 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9253 : {
9254 1786540 : m_poPrivate->m_iCurLayer++;
9255 1786540 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9256 : {
9257 1753870 : m_poPrivate->m_poLayer =
9258 1753870 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9259 : }
9260 : else
9261 : {
9262 32668 : m_poPrivate->m_poLayer = nullptr;
9263 : }
9264 1786540 : return *this;
9265 : }
9266 :
9267 2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9268 : {
9269 2 : GDALDataset::Layers::Iterator temp = *this;
9270 2 : ++(*this);
9271 2 : return temp;
9272 : }
9273 :
9274 1841970 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9275 : {
9276 1841970 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9277 : }
9278 :
9279 : /************************************************************************/
9280 : /* GetLayers() */
9281 : /************************************************************************/
9282 :
9283 : /** Function that returns an iterable object over layers in the dataset.
9284 : *
9285 : * This is a C++ iterator friendly version of GetLayer().
9286 : *
9287 : * Typical use is:
9288 : * \code{.cpp}
9289 : * for( auto&& poLayer: poDS->GetLayers() )
9290 : * {
9291 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9292 : * }
9293 : * \endcode
9294 : *
9295 : * @see GetLayer()
9296 : *
9297 : */
9298 55437 : GDALDataset::Layers GDALDataset::GetLayers()
9299 : {
9300 55437 : return Layers(this);
9301 : }
9302 :
9303 : /************************************************************************/
9304 : /* begin() */
9305 : /************************************************************************/
9306 :
9307 : /**
9308 : \brief Return beginning of layer iterator.
9309 :
9310 : */
9311 :
9312 55436 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9313 : {
9314 55436 : return {m_poSelf, true};
9315 : }
9316 :
9317 : /************************************************************************/
9318 : /* end() */
9319 : /************************************************************************/
9320 :
9321 : /**
9322 : \brief Return end of layer iterator.
9323 :
9324 : */
9325 :
9326 55432 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9327 : {
9328 55432 : return {m_poSelf, false};
9329 : }
9330 :
9331 : /************************************************************************/
9332 : /* size() */
9333 : /************************************************************************/
9334 :
9335 : /**
9336 : \brief Get the number of layers in this dataset.
9337 :
9338 : @return layer count.
9339 :
9340 : */
9341 :
9342 1 : size_t GDALDataset::Layers::size() const
9343 : {
9344 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9345 : }
9346 :
9347 : /************************************************************************/
9348 : /* operator[]() */
9349 : /************************************************************************/
9350 : /**
9351 : \brief Fetch a layer by index.
9352 :
9353 : The returned layer remains owned by the
9354 : GDALDataset and should not be deleted by the application.
9355 :
9356 : @param iLayer a layer number between 0 and size()-1.
9357 :
9358 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9359 :
9360 : */
9361 :
9362 9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9363 : {
9364 9 : return m_poSelf->GetLayer(iLayer);
9365 : }
9366 :
9367 : /************************************************************************/
9368 : /* operator[]() */
9369 : /************************************************************************/
9370 : /**
9371 : \brief Fetch a layer by index.
9372 :
9373 : The returned layer remains owned by the
9374 : GDALDataset and should not be deleted by the application.
9375 :
9376 : @param iLayer a layer number between 0 and size()-1.
9377 :
9378 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9379 :
9380 : */
9381 :
9382 1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9383 : {
9384 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9385 : }
9386 :
9387 : /************************************************************************/
9388 : /* operator[]() */
9389 : /************************************************************************/
9390 : /**
9391 : \brief Fetch a layer by name.
9392 :
9393 : The returned layer remains owned by the
9394 : GDALDataset and should not be deleted by the application.
9395 :
9396 : @param pszLayerName layer name
9397 :
9398 : @return the layer, or nullptr if pszLayerName does not match with a layer
9399 :
9400 : */
9401 :
9402 1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9403 : {
9404 1 : return m_poSelf->GetLayerByName(pszLayerName);
9405 : }
9406 :
9407 : /************************************************************************/
9408 : /* GDALDataset::ConstLayers::Iterator::Private */
9409 : /************************************************************************/
9410 :
9411 : struct GDALDataset::ConstLayers::Iterator::Private
9412 : {
9413 : const OGRLayer *m_poLayer = nullptr;
9414 : int m_iCurLayer = 0;
9415 : int m_nLayerCount = 0;
9416 : const GDALDataset *m_poDS = nullptr;
9417 : };
9418 :
9419 2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9420 : {
9421 2 : }
9422 :
9423 : // False positive of cppcheck 1.72
9424 : // cppcheck-suppress uninitMemberVar
9425 9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9426 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9427 : {
9428 9 : }
9429 :
9430 5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9431 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9432 : {
9433 5 : }
9434 :
9435 35988 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9436 35988 : bool bStart)
9437 35988 : : m_poPrivate(new Private())
9438 : {
9439 35988 : m_poPrivate->m_poDS = poDS;
9440 35988 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9441 35988 : if (bStart)
9442 : {
9443 17996 : if (m_poPrivate->m_nLayerCount)
9444 241 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9445 : }
9446 : else
9447 : {
9448 17992 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9449 : }
9450 35988 : }
9451 :
9452 : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9453 :
9454 : // False positive of cppcheck 1.72
9455 : // cppcheck-suppress operatorEqVarError
9456 : GDALDataset::ConstLayers::Iterator &
9457 1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9458 : {
9459 1 : *m_poPrivate = *oOther.m_poPrivate;
9460 1 : return *this;
9461 : }
9462 :
9463 : GDALDataset::ConstLayers::Iterator &
9464 3 : GDALDataset::ConstLayers::Iterator::operator=(
9465 : GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9466 : {
9467 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9468 3 : return *this;
9469 : }
9470 :
9471 16205 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9472 : {
9473 16205 : return m_poPrivate->m_poLayer;
9474 : }
9475 :
9476 : GDALDataset::ConstLayers::Iterator &
9477 16198 : GDALDataset::ConstLayers::Iterator::operator++()
9478 : {
9479 16198 : m_poPrivate->m_iCurLayer++;
9480 16198 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9481 : {
9482 15970 : m_poPrivate->m_poLayer =
9483 15970 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9484 : }
9485 : else
9486 : {
9487 228 : m_poPrivate->m_poLayer = nullptr;
9488 : }
9489 16198 : return *this;
9490 : }
9491 :
9492 : GDALDataset::ConstLayers::Iterator
9493 2 : GDALDataset::ConstLayers::Iterator::operator++(int)
9494 : {
9495 2 : GDALDataset::ConstLayers::Iterator temp = *this;
9496 2 : ++(*this);
9497 2 : return temp;
9498 : }
9499 :
9500 34184 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9501 : {
9502 34184 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9503 : }
9504 :
9505 : /************************************************************************/
9506 : /* GetLayers() */
9507 : /************************************************************************/
9508 :
9509 : /** Function that returns an iterable object over layers in the dataset.
9510 : *
9511 : * This is a C++ iterator friendly version of GetLayer().
9512 : *
9513 : * Typical use is:
9514 : * \code{.cpp}
9515 : * for( auto&& poLayer: poDS->GetLayers() )
9516 : * {
9517 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9518 : * }
9519 : * \endcode
9520 : *
9521 : * @see GetLayer()
9522 : *
9523 : * @since GDAL 3.12
9524 : */
9525 17997 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
9526 : {
9527 17997 : return ConstLayers(this);
9528 : }
9529 :
9530 : /************************************************************************/
9531 : /* begin() */
9532 : /************************************************************************/
9533 :
9534 : /**
9535 : \brief Return beginning of layer iterator.
9536 :
9537 : @since GDAL 3.12
9538 : */
9539 :
9540 17996 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9541 : {
9542 17996 : return {m_poSelf, true};
9543 : }
9544 :
9545 : /************************************************************************/
9546 : /* end() */
9547 : /************************************************************************/
9548 :
9549 : /**
9550 : \brief Return end of layer iterator.
9551 :
9552 : @since GDAL 3.12
9553 : */
9554 :
9555 17992 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9556 : {
9557 17992 : return {m_poSelf, false};
9558 : }
9559 :
9560 : /************************************************************************/
9561 : /* size() */
9562 : /************************************************************************/
9563 :
9564 : /**
9565 : \brief Get the number of layers in this dataset.
9566 :
9567 : @return layer count.
9568 :
9569 : @since GDAL 3.12
9570 : */
9571 :
9572 1 : size_t GDALDataset::ConstLayers::size() const
9573 : {
9574 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9575 : }
9576 :
9577 : /************************************************************************/
9578 : /* operator[]() */
9579 : /************************************************************************/
9580 : /**
9581 : \brief Fetch a layer by index.
9582 :
9583 : The returned layer remains owned by the
9584 : GDALDataset and should not be deleted by the application.
9585 :
9586 : @param iLayer a layer number between 0 and size()-1.
9587 :
9588 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9589 :
9590 : @since GDAL 3.12
9591 : */
9592 :
9593 9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9594 : {
9595 9 : return m_poSelf->GetLayer(iLayer);
9596 : }
9597 :
9598 : /************************************************************************/
9599 : /* operator[]() */
9600 : /************************************************************************/
9601 : /**
9602 : \brief Fetch a layer by index.
9603 :
9604 : The returned layer remains owned by the
9605 : GDALDataset and should not be deleted by the application.
9606 :
9607 : @param iLayer a layer number between 0 and size()-1.
9608 :
9609 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9610 :
9611 : @since GDAL 3.12
9612 : */
9613 :
9614 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9615 : {
9616 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9617 : }
9618 :
9619 : /************************************************************************/
9620 : /* operator[]() */
9621 : /************************************************************************/
9622 : /**
9623 : \brief Fetch a layer by name.
9624 :
9625 : The returned layer remains owned by the
9626 : GDALDataset and should not be deleted by the application.
9627 :
9628 : @param pszLayerName layer name
9629 :
9630 : @return the layer, or nullptr if pszLayerName does not match with a layer
9631 :
9632 : @since GDAL 3.12
9633 : */
9634 :
9635 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9636 : {
9637 1 : return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9638 : }
9639 :
9640 : /************************************************************************/
9641 : /* GDALDataset::Bands::Iterator::Private */
9642 : /************************************************************************/
9643 :
9644 : struct GDALDataset::Bands::Iterator::Private
9645 : {
9646 : GDALRasterBand *m_poBand = nullptr;
9647 : int m_iCurBand = 0;
9648 : int m_nBandCount = 0;
9649 : GDALDataset *m_poDS = nullptr;
9650 : };
9651 :
9652 32 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9653 32 : : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9654 : {
9655 32 : m_poPrivate->m_poDS = poDS;
9656 32 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9657 32 : if (bStart)
9658 : {
9659 16 : if (m_poPrivate->m_nBandCount)
9660 16 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9661 : }
9662 : else
9663 : {
9664 16 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9665 : }
9666 32 : }
9667 :
9668 : GDALDataset::Bands::Iterator::~Iterator() = default;
9669 :
9670 18 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9671 : {
9672 18 : return m_poPrivate->m_poBand;
9673 : }
9674 :
9675 4 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9676 : {
9677 4 : m_poPrivate->m_iCurBand++;
9678 4 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9679 : {
9680 2 : m_poPrivate->m_poBand =
9681 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9682 : }
9683 : else
9684 : {
9685 2 : m_poPrivate->m_poBand = nullptr;
9686 : }
9687 4 : return *this;
9688 : }
9689 :
9690 20 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9691 : {
9692 20 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9693 : }
9694 :
9695 : /************************************************************************/
9696 : /* GetBands() */
9697 : /************************************************************************/
9698 :
9699 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9700 : *
9701 : * This is a C++ iterator friendly version of GetRasterBand().
9702 : *
9703 : * Typical use is:
9704 : * \code{.cpp}
9705 : * for( auto&& poBand: poDS->GetBands() )
9706 : * {
9707 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9708 : * }
9709 : * \endcode
9710 : *
9711 : * @see GetRasterBand()
9712 : *
9713 : */
9714 20 : GDALDataset::Bands GDALDataset::GetBands()
9715 : {
9716 20 : return Bands(this);
9717 : }
9718 :
9719 : /************************************************************************/
9720 : /* begin() */
9721 : /************************************************************************/
9722 :
9723 : /**
9724 : \brief Return beginning of band iterator.
9725 :
9726 : */
9727 :
9728 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9729 : {
9730 16 : return {m_poSelf, true};
9731 : }
9732 :
9733 : /************************************************************************/
9734 : /* end() */
9735 : /************************************************************************/
9736 :
9737 : /**
9738 : \brief Return end of band iterator.
9739 :
9740 : */
9741 :
9742 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9743 : {
9744 16 : return {m_poSelf, false};
9745 : }
9746 :
9747 : /************************************************************************/
9748 : /* size() */
9749 : /************************************************************************/
9750 :
9751 : /**
9752 : \brief Get the number of raster bands in this dataset.
9753 :
9754 : @return raster band count.
9755 :
9756 : */
9757 :
9758 2 : size_t GDALDataset::Bands::size() const
9759 : {
9760 2 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9761 : }
9762 :
9763 : /************************************************************************/
9764 : /* operator[]() */
9765 : /************************************************************************/
9766 : /**
9767 : \brief Fetch a raster band by index.
9768 :
9769 : The returned band remains owned by the
9770 : GDALDataset and should not be deleted by the application.
9771 :
9772 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9773 : consistent with the conventions of C/C++, i.e. starting at 0.
9774 :
9775 : @param iBand a band index between 0 and size()-1.
9776 :
9777 : @return the band, or nullptr if iBand is out of range or an error occurs.
9778 :
9779 : */
9780 :
9781 1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9782 : {
9783 1 : return m_poSelf->GetRasterBand(1 + iBand);
9784 : }
9785 :
9786 : /************************************************************************/
9787 : /* operator[]() */
9788 : /************************************************************************/
9789 :
9790 : /**
9791 : \brief Fetch a raster band by index.
9792 :
9793 : The returned band remains owned by the
9794 : GDALDataset and should not be deleted by the application.
9795 :
9796 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9797 : consistent with the conventions of C/C++, i.e. starting at 0.
9798 :
9799 : @param iBand a band index between 0 and size()-1.
9800 :
9801 : @return the band, or nullptr if iBand is out of range or an error occurs.
9802 :
9803 : */
9804 :
9805 1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9806 : {
9807 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9808 : }
9809 :
9810 : /************************************************************************/
9811 : /* GDALDataset::ConstBands::Iterator::Private */
9812 : /************************************************************************/
9813 :
9814 : struct GDALDataset::ConstBands::Iterator::Private
9815 : {
9816 : const GDALRasterBand *m_poBand = nullptr;
9817 : int m_iCurBand = 0;
9818 : int m_nBandCount = 0;
9819 : const GDALDataset *m_poDS = nullptr;
9820 : };
9821 :
9822 2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9823 2 : bool bStart)
9824 2 : : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9825 : {
9826 2 : m_poPrivate->m_poDS = poDS;
9827 2 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9828 2 : if (bStart)
9829 : {
9830 1 : if (m_poPrivate->m_nBandCount)
9831 1 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9832 : }
9833 : else
9834 : {
9835 1 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9836 : }
9837 2 : }
9838 :
9839 : GDALDataset::ConstBands::Iterator::~Iterator() = default;
9840 :
9841 3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9842 : {
9843 3 : return m_poPrivate->m_poBand;
9844 : }
9845 :
9846 : GDALDataset::ConstBands::Iterator &
9847 3 : GDALDataset::ConstBands::Iterator::operator++()
9848 : {
9849 3 : m_poPrivate->m_iCurBand++;
9850 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9851 : {
9852 2 : m_poPrivate->m_poBand =
9853 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9854 : }
9855 : else
9856 : {
9857 1 : m_poPrivate->m_poBand = nullptr;
9858 : }
9859 3 : return *this;
9860 : }
9861 :
9862 4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9863 : {
9864 4 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9865 : }
9866 :
9867 : /************************************************************************/
9868 : /* GetBands() */
9869 : /************************************************************************/
9870 :
9871 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9872 : *
9873 : * This is a C++ iterator friendly version of GetRasterBand().
9874 : *
9875 : * Typical use is:
9876 : * \code{.cpp}
9877 : * for( const auto* poBand: poDS->GetConstBands() )
9878 : * {
9879 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9880 : * }
9881 : * \endcode
9882 : *
9883 : * @see GetRasterBand()
9884 : *
9885 : * @since GDAL 3.12
9886 : */
9887 4 : GDALDataset::ConstBands GDALDataset::GetBands() const
9888 : {
9889 4 : return ConstBands(this);
9890 : }
9891 :
9892 : /************************************************************************/
9893 : /* begin() */
9894 : /************************************************************************/
9895 :
9896 : /**
9897 : \brief Return beginning of band iterator.
9898 :
9899 : @since GDAL 3.12
9900 : */
9901 :
9902 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9903 : {
9904 1 : return {m_poSelf, true};
9905 : }
9906 :
9907 : /************************************************************************/
9908 : /* end() */
9909 : /************************************************************************/
9910 :
9911 : /**
9912 : \brief Return end of band iterator.
9913 :
9914 : @since GDAL 3.12
9915 : */
9916 :
9917 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9918 : {
9919 1 : return {m_poSelf, false};
9920 : }
9921 :
9922 : /************************************************************************/
9923 : /* size() */
9924 : /************************************************************************/
9925 :
9926 : /**
9927 : \brief Get the number of raster bands in this dataset.
9928 :
9929 : @return raster band count.
9930 :
9931 : @since GDAL 3.12
9932 : */
9933 :
9934 1 : size_t GDALDataset::ConstBands::size() const
9935 : {
9936 1 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9937 : }
9938 :
9939 : /************************************************************************/
9940 : /* operator[]() */
9941 : /************************************************************************/
9942 : /**
9943 : \brief Fetch a raster band by index.
9944 :
9945 : The returned band remains owned by the
9946 : GDALDataset and should not be deleted by the application.
9947 :
9948 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9949 : consistent with the conventions of C/C++, i.e. starting at 0.
9950 :
9951 : @param iBand a band index between 0 and size()-1.
9952 :
9953 : @return the band, or nullptr if iBand is out of range or an error occurs.
9954 :
9955 : @since GDAL 3.12
9956 : */
9957 :
9958 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9959 : {
9960 1 : return m_poSelf->GetRasterBand(1 + iBand);
9961 : }
9962 :
9963 : /************************************************************************/
9964 : /* operator[]() */
9965 : /************************************************************************/
9966 :
9967 : /**
9968 : \brief Fetch a raster band by index.
9969 :
9970 : The returned band remains owned by the
9971 : GDALDataset and should not be deleted by the application.
9972 :
9973 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9974 : consistent with the conventions of C/C++, i.e. starting at 0.
9975 :
9976 : @param iBand a band index between 0 and size()-1.
9977 :
9978 : @return the band, or nullptr if iBand is out of range or an error occurs.
9979 :
9980 : @since GDAL 3.12
9981 : */
9982 :
9983 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9984 : {
9985 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9986 : }
9987 :
9988 : /************************************************************************/
9989 : /* GetRootGroup() */
9990 : /************************************************************************/
9991 :
9992 : /**
9993 : \brief Return the root GDALGroup of this dataset.
9994 :
9995 : Only valid for multidimensional datasets.
9996 :
9997 : This is the same as the C function GDALDatasetGetRootGroup().
9998 :
9999 : @since GDAL 3.1
10000 : */
10001 :
10002 2990 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
10003 : {
10004 2990 : return nullptr;
10005 : }
10006 :
10007 : /************************************************************************/
10008 : /* GDALDatasetGetRootGroup() */
10009 : /************************************************************************/
10010 :
10011 : /** Return the root GDALGroup of this dataset.
10012 : *
10013 : * Only valid for multidimensional datasets.
10014 : *
10015 : * The returned value must be freed with GDALGroupRelease().
10016 : *
10017 : * This is the same as the C++ method GDALDataset::GetRootGroup().
10018 : *
10019 : * @since GDAL 3.1
10020 : */
10021 2205 : GDALGroupH GDALDatasetGetRootGroup(GDALDatasetH hDS)
10022 : {
10023 2205 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10024 2205 : auto poGroup(GDALDataset::FromHandle(hDS)->GetRootGroup());
10025 2205 : return poGroup ? new GDALGroupHS(poGroup) : nullptr;
10026 : }
10027 :
10028 : /************************************************************************/
10029 : /* GDALDatasetAsMDArray() */
10030 : /************************************************************************/
10031 :
10032 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
10033 : *
10034 : * If this dataset is not already marked as shared, it will be, so that the
10035 : * returned array holds a reference to it.
10036 : *
10037 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10038 : * returned array will have an associated indexing variable.
10039 : *
10040 : * The currently supported list of options is:
10041 : * <ul>
10042 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
10043 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
10044 : * and the last (fastest changing direction) is X
10045 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
10046 : * and the last (fastest changing direction) is Band.
10047 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
10048 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
10049 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
10050 : * "Y,X,Band" is use.
10051 : * </li>
10052 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
10053 : * item from which to build the band indexing variable.
10054 : * <ul>
10055 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
10056 : * <li>"{None}" means that no band indexing variable must be created.</li>
10057 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
10058 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
10059 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
10060 : * </ul>
10061 : * </li>
10062 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
10063 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
10064 : * Defaults to String.
10065 : * </li>
10066 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
10067 : * Defaults to "Band".
10068 : * </li>
10069 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
10070 : * </li>
10071 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
10072 : * </li>
10073 : * </ul>
10074 : *
10075 : * The returned pointer must be released with GDALMDArrayRelease().
10076 : *
10077 : * The "reverse" methods are GDALRasterBand::AsMDArray() and
10078 : * GDALDataset::AsMDArray()
10079 : *
10080 : * This is the same as the C++ method GDALDataset::AsMDArray().
10081 : *
10082 : * @param hDS Dataset handle.
10083 : * @param papszOptions Null-terminated list of strings, or nullptr.
10084 : * @return a new array, or NULL.
10085 : *
10086 : * @since GDAL 3.12
10087 : */
10088 15 : GDALMDArrayH GDALDatasetAsMDArray(GDALDatasetH hDS, CSLConstList papszOptions)
10089 : {
10090 15 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10091 30 : auto poArray(GDALDataset::FromHandle(hDS)->AsMDArray(papszOptions));
10092 15 : if (!poArray)
10093 3 : return nullptr;
10094 12 : return new GDALMDArrayHS(poArray);
10095 : }
10096 :
10097 : /************************************************************************/
10098 : /* GetRawBinaryLayout() */
10099 : /************************************************************************/
10100 :
10101 : //! @cond Doxygen_Suppress
10102 : /**
10103 : \brief Return the layout of a dataset that can be considered as a raw binary
10104 : format.
10105 :
10106 : @param sLayout Structure that will be set if the dataset is a raw binary one.
10107 : @return true if the dataset is a raw binary one.
10108 : @since GDAL 3.1
10109 : */
10110 :
10111 0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
10112 : {
10113 0 : CPL_IGNORE_RET_VAL(sLayout);
10114 0 : return false;
10115 : }
10116 :
10117 : //! @endcond
10118 :
10119 : /************************************************************************/
10120 : /* ClearStatistics() */
10121 : /************************************************************************/
10122 :
10123 : /**
10124 : \brief Clear statistics
10125 :
10126 : Only implemented for now in PAM supported datasets
10127 :
10128 : This is the same as the C function GDALDatasetClearStatistics().
10129 :
10130 : @since GDAL 3.2
10131 : */
10132 :
10133 11 : void GDALDataset::ClearStatistics()
10134 : {
10135 22 : auto poRootGroup = GetRootGroup();
10136 11 : if (poRootGroup)
10137 1 : poRootGroup->ClearStatistics();
10138 11 : }
10139 :
10140 : /************************************************************************/
10141 : /* GDALDatasetClearStatistics() */
10142 : /************************************************************************/
10143 :
10144 : /**
10145 : \brief Clear statistics
10146 :
10147 : This is the same as the C++ method GDALDataset::ClearStatistics().
10148 :
10149 : @since GDAL 3.2
10150 : */
10151 :
10152 2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
10153 : {
10154 2 : VALIDATE_POINTER0(hDS, __func__);
10155 2 : GDALDataset::FromHandle(hDS)->ClearStatistics();
10156 : }
10157 :
10158 : /************************************************************************/
10159 : /* GetFieldDomainNames() */
10160 : /************************************************************************/
10161 :
10162 : /** Returns a list of the names of all field domains stored in the dataset.
10163 : *
10164 : * @note The default implementation assumes that drivers fully populate
10165 : * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10166 : * then a specialized implementation of GetFieldDomainNames() must be
10167 : * implemented.
10168 : *
10169 : * @param papszOptions Driver specific options determining how attributes
10170 : * should be retrieved. Pass nullptr for default behavior.
10171 : *
10172 : * @return list of field domain names
10173 : * @since GDAL 3.5
10174 : */
10175 : std::vector<std::string>
10176 47 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10177 : {
10178 :
10179 47 : std::vector<std::string> names;
10180 47 : names.reserve(m_oMapFieldDomains.size());
10181 59 : for (const auto &it : m_oMapFieldDomains)
10182 : {
10183 12 : names.emplace_back(it.first);
10184 : }
10185 47 : return names;
10186 : }
10187 :
10188 : /************************************************************************/
10189 : /* GDALDatasetGetFieldDomainNames() */
10190 : /************************************************************************/
10191 :
10192 : /** Returns a list of the names of all field domains stored in the dataset.
10193 : *
10194 : * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10195 : *
10196 : * @param hDS Dataset handle.
10197 : * @param papszOptions Driver specific options determining how attributes
10198 : * should be retrieved. Pass nullptr for default behavior.
10199 : *
10200 : * @return list of field domain names, to be freed with CSLDestroy()
10201 : * @since GDAL 3.5
10202 : */
10203 40 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10204 : CSLConstList papszOptions)
10205 : {
10206 40 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10207 : auto names =
10208 80 : GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10209 80 : CPLStringList res;
10210 196 : for (const auto &name : names)
10211 : {
10212 156 : res.AddString(name.c_str());
10213 : }
10214 40 : return res.StealList();
10215 : }
10216 :
10217 : /************************************************************************/
10218 : /* GetFieldDomain() */
10219 : /************************************************************************/
10220 :
10221 : /** Get a field domain from its name.
10222 : *
10223 : * @return the field domain, or nullptr if not found.
10224 : * @since GDAL 3.3
10225 : */
10226 328 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10227 : {
10228 328 : const auto iter = m_oMapFieldDomains.find(name);
10229 328 : if (iter == m_oMapFieldDomains.end())
10230 153 : return nullptr;
10231 175 : return iter->second.get();
10232 : }
10233 :
10234 : /************************************************************************/
10235 : /* GDALDatasetGetFieldDomain() */
10236 : /************************************************************************/
10237 :
10238 : /** Get a field domain from its name.
10239 : *
10240 : * This is the same as the C++ method GDALDataset::GetFieldDomain().
10241 : *
10242 : * @param hDS Dataset handle.
10243 : * @param pszName Name of field domain.
10244 : * @return the field domain (ownership remains to the dataset), or nullptr if
10245 : * not found.
10246 : * @since GDAL 3.3
10247 : */
10248 133 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10249 : {
10250 133 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10251 133 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10252 133 : return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10253 133 : GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10254 : }
10255 :
10256 : /************************************************************************/
10257 : /* AddFieldDomain() */
10258 : /************************************************************************/
10259 :
10260 : /** Add a field domain to the dataset.
10261 : *
10262 : * Only a few drivers will support this operation, and some of them might only
10263 : * support it only for some types of field domains.
10264 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10265 : * support this operation. A dataset having at least some support for this
10266 : * operation should report the ODsCAddFieldDomain dataset capability.
10267 : *
10268 : * Anticipated failures will not be emitted through the CPLError()
10269 : * infrastructure, but will be reported in the failureReason output parameter.
10270 : *
10271 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10272 : * default implementation of GetFieldDomainNames() to work correctly, or
10273 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10274 : * implemented.
10275 : *
10276 : * @param domain The domain definition.
10277 : * @param failureReason Output parameter. Will contain an error message if
10278 : * an error occurs.
10279 : * @return true in case of success.
10280 : * @since GDAL 3.3
10281 : */
10282 0 : bool GDALDataset::AddFieldDomain(
10283 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10284 : std::string &failureReason)
10285 : {
10286 0 : failureReason = "AddFieldDomain not supported by this driver";
10287 0 : return false;
10288 : }
10289 :
10290 : /************************************************************************/
10291 : /* GDALDatasetAddFieldDomain() */
10292 : /************************************************************************/
10293 :
10294 : /** Add a field domain to the dataset.
10295 : *
10296 : * Only a few drivers will support this operation, and some of them might only
10297 : * support it only for some types of field domains.
10298 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10299 : * support this operation. A dataset having at least some support for this
10300 : * operation should report the ODsCAddFieldDomain dataset capability.
10301 : *
10302 : * Anticipated failures will not be emitted through the CPLError()
10303 : * infrastructure, but will be reported in the ppszFailureReason output
10304 : * parameter.
10305 : *
10306 : * @param hDS Dataset handle.
10307 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10308 : * the passed object is copied.
10309 : * @param ppszFailureReason Output parameter. Will contain an error message if
10310 : * an error occurs (*ppszFailureReason to be freed
10311 : * with CPLFree). May be NULL.
10312 : * @return true in case of success.
10313 : * @since GDAL 3.3
10314 : */
10315 37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10316 : char **ppszFailureReason)
10317 : {
10318 37 : VALIDATE_POINTER1(hDS, __func__, false);
10319 37 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10320 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10321 74 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10322 37 : if (poDomain == nullptr)
10323 0 : return false;
10324 37 : std::string failureReason;
10325 74 : const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10326 37 : std::move(poDomain), failureReason);
10327 37 : if (ppszFailureReason)
10328 : {
10329 37 : *ppszFailureReason =
10330 37 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10331 : }
10332 37 : return bRet;
10333 : }
10334 :
10335 : /************************************************************************/
10336 : /* DeleteFieldDomain() */
10337 : /************************************************************************/
10338 :
10339 : /** Removes a field domain from the dataset.
10340 : *
10341 : * Only a few drivers will support this operation.
10342 : *
10343 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10344 : * support this operation. A dataset having at least some support for this
10345 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10346 : *
10347 : * Anticipated failures will not be emitted through the CPLError()
10348 : * infrastructure, but will be reported in the failureReason output parameter.
10349 : *
10350 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10351 : * default implementation of GetFieldDomainNames() to work correctly, or
10352 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10353 : * implemented.
10354 : *
10355 : * @param name The domain name.
10356 : * @param failureReason Output parameter. Will contain an error message if
10357 : * an error occurs.
10358 : * @return true in case of success.
10359 : * @since GDAL 3.5
10360 : */
10361 0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10362 : std::string &failureReason)
10363 : {
10364 0 : failureReason = "DeleteFieldDomain not supported by this driver";
10365 0 : return false;
10366 : }
10367 :
10368 : /************************************************************************/
10369 : /* GDALDatasetDeleteFieldDomain() */
10370 : /************************************************************************/
10371 :
10372 : /** Removes a field domain from the dataset.
10373 : *
10374 : * Only a few drivers will support this operation.
10375 : *
10376 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10377 : * support this operation. A dataset having at least some support for this
10378 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10379 : *
10380 : * Anticipated failures will not be emitted through the CPLError()
10381 : * infrastructure, but will be reported in the ppszFailureReason output
10382 : * parameter.
10383 : *
10384 : * @param hDS Dataset handle.
10385 : * @param pszName The domain name.
10386 : * @param ppszFailureReason Output parameter. Will contain an error message if
10387 : * an error occurs (*ppszFailureReason to be freed
10388 : * with CPLFree). May be NULL.
10389 : * @return true in case of success.
10390 : * @since GDAL 3.3
10391 : */
10392 25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10393 : char **ppszFailureReason)
10394 : {
10395 25 : VALIDATE_POINTER1(hDS, __func__, false);
10396 25 : VALIDATE_POINTER1(pszName, __func__, false);
10397 25 : std::string failureReason;
10398 : const bool bRet =
10399 25 : GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10400 25 : if (ppszFailureReason)
10401 : {
10402 0 : *ppszFailureReason =
10403 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10404 : }
10405 25 : return bRet;
10406 : }
10407 :
10408 : /************************************************************************/
10409 : /* UpdateFieldDomain() */
10410 : /************************************************************************/
10411 :
10412 : /** Updates an existing field domain by replacing its definition.
10413 : *
10414 : * The existing field domain with matching name will be replaced.
10415 : *
10416 : * Only a few drivers will support this operation, and some of them might only
10417 : * support it only for some types of field domains.
10418 : * At the time of writing (GDAL 3.5), only the Memory driver
10419 : * supports this operation. A dataset having at least some support for this
10420 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10421 : *
10422 : * Anticipated failures will not be emitted through the CPLError()
10423 : * infrastructure, but will be reported in the failureReason output parameter.
10424 : *
10425 : * @param domain The domain definition.
10426 : * @param failureReason Output parameter. Will contain an error message if
10427 : * an error occurs.
10428 : * @return true in case of success.
10429 : * @since GDAL 3.5
10430 : */
10431 0 : bool GDALDataset::UpdateFieldDomain(
10432 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10433 : std::string &failureReason)
10434 : {
10435 0 : failureReason = "UpdateFieldDomain not supported by this driver";
10436 0 : return false;
10437 : }
10438 :
10439 : /************************************************************************/
10440 : /* GDALDatasetUpdateFieldDomain() */
10441 : /************************************************************************/
10442 :
10443 : /** Updates an existing field domain by replacing its definition.
10444 : *
10445 : * The existing field domain with matching name will be replaced.
10446 : *
10447 : * Only a few drivers will support this operation, and some of them might only
10448 : * support it only for some types of field domains.
10449 : * At the time of writing (GDAL 3.5), only the Memory driver
10450 : * supports this operation. A dataset having at least some support for this
10451 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10452 : *
10453 : * Anticipated failures will not be emitted through the CPLError()
10454 : * infrastructure, but will be reported in the failureReason output parameter.
10455 : *
10456 : * @param hDS Dataset handle.
10457 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10458 : * the passed object is copied.
10459 : * @param ppszFailureReason Output parameter. Will contain an error message if
10460 : * an error occurs (*ppszFailureReason to be freed
10461 : * with CPLFree). May be NULL.
10462 : * @return true in case of success.
10463 : * @since GDAL 3.5
10464 : */
10465 7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10466 : OGRFieldDomainH hFieldDomain,
10467 : char **ppszFailureReason)
10468 : {
10469 7 : VALIDATE_POINTER1(hDS, __func__, false);
10470 7 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10471 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10472 14 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10473 7 : if (poDomain == nullptr)
10474 0 : return false;
10475 7 : std::string failureReason;
10476 14 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10477 7 : std::move(poDomain), failureReason);
10478 7 : if (ppszFailureReason)
10479 : {
10480 0 : *ppszFailureReason =
10481 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10482 : }
10483 7 : return bRet;
10484 : }
10485 :
10486 : /************************************************************************/
10487 : /* GetRelationshipNames() */
10488 : /************************************************************************/
10489 :
10490 : /** Returns a list of the names of all relationships stored in the dataset.
10491 : *
10492 : * @param papszOptions Driver specific options determining how relationships
10493 : * should be retrieved. Pass nullptr for default behavior.
10494 : *
10495 : * @return list of relationship names
10496 : * @since GDAL 3.6
10497 : */
10498 : std::vector<std::string>
10499 252 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10500 : {
10501 252 : return {};
10502 : }
10503 :
10504 : /************************************************************************/
10505 : /* GDALDatasetGetRelationshipNames() */
10506 : /************************************************************************/
10507 :
10508 : /** Returns a list of the names of all relationships stored in the dataset.
10509 : *
10510 : * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10511 : *
10512 : * @param hDS Dataset handle.
10513 : * @param papszOptions Driver specific options determining how relationships
10514 : * should be retrieved. Pass nullptr for default behavior.
10515 : *
10516 : * @return list of relationship names, to be freed with CSLDestroy()
10517 : * @since GDAL 3.6
10518 : */
10519 53 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10520 : CSLConstList papszOptions)
10521 : {
10522 53 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10523 : auto names =
10524 106 : GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10525 106 : CPLStringList res;
10526 161 : for (const auto &name : names)
10527 : {
10528 108 : res.AddString(name.c_str());
10529 : }
10530 53 : return res.StealList();
10531 : }
10532 :
10533 : /************************************************************************/
10534 : /* GetRelationship() */
10535 : /************************************************************************/
10536 :
10537 : /** Get a relationship from its name.
10538 : *
10539 : * @return the relationship, or nullptr if not found.
10540 : * @since GDAL 3.6
10541 : */
10542 : const GDALRelationship *
10543 0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10544 : {
10545 0 : return nullptr;
10546 : }
10547 :
10548 : /************************************************************************/
10549 : /* GDALDatasetGetRelationship() */
10550 : /************************************************************************/
10551 :
10552 : /** Get a relationship from its name.
10553 : *
10554 : * This is the same as the C++ method GDALDataset::GetRelationship().
10555 : *
10556 : * @param hDS Dataset handle.
10557 : * @param pszName Name of relationship.
10558 : * @return the relationship (ownership remains to the dataset), or nullptr if
10559 : * not found.
10560 : * @since GDAL 3.6
10561 : */
10562 63 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10563 : const char *pszName)
10564 : {
10565 63 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10566 63 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10567 63 : return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10568 63 : GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10569 : }
10570 :
10571 : /************************************************************************/
10572 : /* AddRelationship() */
10573 : /************************************************************************/
10574 :
10575 : /** Add a relationship to the dataset.
10576 : *
10577 : * Only a few drivers will support this operation, and some of them might only
10578 : * support it only for some types of relationships.
10579 : *
10580 : * A dataset having at least some support for this
10581 : * operation should report the GDsCAddRelationship dataset capability.
10582 : *
10583 : * Anticipated failures will not be emitted through the CPLError()
10584 : * infrastructure, but will be reported in the failureReason output parameter.
10585 : *
10586 : * When adding a many-to-many relationship
10587 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10588 : * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10589 : * the driver to create an appropriately named and structured mapping table.
10590 : * Some dataset formats require particular naming conventions and field
10591 : * structures for the mapping table, and delegating the construction of the
10592 : * mapping table to the driver will avoid these pitfalls.
10593 : *
10594 : * @param relationship The relationship definition.
10595 : * @param failureReason Output parameter. Will contain an error message if
10596 : * an error occurs.
10597 : * @return true in case of success.
10598 : * @since GDAL 3.6
10599 : */
10600 0 : bool GDALDataset::AddRelationship(
10601 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10602 : std::string &failureReason)
10603 : {
10604 0 : failureReason = "AddRelationship not supported by this driver";
10605 0 : return false;
10606 : }
10607 :
10608 : /************************************************************************/
10609 : /* GDALDatasetAddRelationship() */
10610 : /************************************************************************/
10611 :
10612 : /** Add a relationship to the dataset.
10613 : *
10614 : * Only a few drivers will support this operation, and some of them might only
10615 : * support it only for some types of relationships.
10616 : *
10617 : * A dataset having at least some support for this
10618 : * operation should report the GDsCAddRelationship dataset capability.
10619 : *
10620 : * Anticipated failures will not be emitted through the CPLError()
10621 : * infrastructure, but will be reported in the failureReason output parameter.
10622 : *
10623 : * When adding a many-to-many relationship
10624 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10625 : * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10626 : * driver to create an appropriately named and structured mapping table. Some
10627 : * dataset formats require particular naming conventions and field structures
10628 : * for the mapping table, and delegating the construction of the mapping table
10629 : * to the driver will avoid these pitfalls.
10630 : *
10631 : * @param hDS Dataset handle.
10632 : * @param hRelationship The relationship definition. Contrary to the C++
10633 : * version, the passed object is copied.
10634 : * @param ppszFailureReason Output parameter. Will contain an error message if
10635 : * an error occurs (*ppszFailureReason to be freed
10636 : * with CPLFree). May be NULL.
10637 : * @return true in case of success.
10638 : * @since GDAL 3.6
10639 : */
10640 45 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10641 : GDALRelationshipH hRelationship,
10642 : char **ppszFailureReason)
10643 : {
10644 45 : VALIDATE_POINTER1(hDS, __func__, false);
10645 45 : VALIDATE_POINTER1(hRelationship, __func__, false);
10646 : std::unique_ptr<GDALRelationship> poRelationship(
10647 90 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10648 45 : std::string failureReason;
10649 90 : const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10650 45 : std::move(poRelationship), failureReason);
10651 45 : if (ppszFailureReason)
10652 : {
10653 0 : *ppszFailureReason =
10654 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10655 : }
10656 45 : return bRet;
10657 : }
10658 :
10659 : /************************************************************************/
10660 : /* DeleteRelationship() */
10661 : /************************************************************************/
10662 :
10663 : /** Removes a relationship from the dataset.
10664 : *
10665 : * Only a few drivers will support this operation.
10666 : *
10667 : * A dataset having at least some support for this
10668 : * operation should report the GDsCDeleteRelationship dataset capability.
10669 : *
10670 : * Anticipated failures will not be emitted through the CPLError()
10671 : * infrastructure, but will be reported in the failureReason output parameter.
10672 : *
10673 : * @param name The relationship name.
10674 : * @param failureReason Output parameter. Will contain an error message if
10675 : * an error occurs.
10676 : * @return true in case of success.
10677 : * @since GDAL 3.6
10678 : */
10679 0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10680 : std::string &failureReason)
10681 : {
10682 0 : failureReason = "DeleteRelationship not supported by this driver";
10683 0 : return false;
10684 : }
10685 :
10686 : /************************************************************************/
10687 : /* GDALDatasetDeleteRelationship() */
10688 : /************************************************************************/
10689 :
10690 : /** Removes a relationship from the dataset.
10691 : *
10692 : * Only a few drivers will support this operation.
10693 : *
10694 : * A dataset having at least some support for this
10695 : * operation should report the GDsCDeleteRelationship dataset capability.
10696 : *
10697 : * Anticipated failures will not be emitted through the CPLError()
10698 : * infrastructure, but will be reported in the ppszFailureReason output
10699 : * parameter.
10700 : *
10701 : * @param hDS Dataset handle.
10702 : * @param pszName The relationship name.
10703 : * @param ppszFailureReason Output parameter. Will contain an error message if
10704 : * an error occurs (*ppszFailureReason to be freed
10705 : * with CPLFree). May be NULL.
10706 : * @return true in case of success.
10707 : * @since GDAL 3.6
10708 : */
10709 8 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10710 : char **ppszFailureReason)
10711 : {
10712 8 : VALIDATE_POINTER1(hDS, __func__, false);
10713 8 : VALIDATE_POINTER1(pszName, __func__, false);
10714 8 : std::string failureReason;
10715 16 : const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10716 8 : pszName, failureReason);
10717 8 : if (ppszFailureReason)
10718 : {
10719 0 : *ppszFailureReason =
10720 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10721 : }
10722 8 : return bRet;
10723 : }
10724 :
10725 : /************************************************************************/
10726 : /* UpdateRelationship() */
10727 : /************************************************************************/
10728 :
10729 : /** Updates an existing relationship by replacing its definition.
10730 : *
10731 : * The existing relationship with matching name will be replaced.
10732 : *
10733 : * Only a few drivers will support this operation, and some of them might only
10734 : * support it only for some types of relationships.
10735 : * A dataset having at least some support for this
10736 : * operation should report the GDsCUpdateRelationship dataset capability.
10737 : *
10738 : * Anticipated failures will not be emitted through the CPLError()
10739 : * infrastructure, but will be reported in the failureReason output parameter.
10740 : *
10741 : * @param relationship The relationship definition.
10742 : * @param failureReason Output parameter. Will contain an error message if
10743 : * an error occurs.
10744 : * @return true in case of success.
10745 : * @since GDAL 3.6
10746 : */
10747 0 : bool GDALDataset::UpdateRelationship(
10748 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10749 : std::string &failureReason)
10750 : {
10751 0 : failureReason = "UpdateRelationship not supported by this driver";
10752 0 : return false;
10753 : }
10754 :
10755 : /************************************************************************/
10756 : /* GDALDatasetUpdateRelationship() */
10757 : /************************************************************************/
10758 :
10759 : /** Updates an existing relationship by replacing its definition.
10760 : *
10761 : * The existing relationship with matching name will be replaced.
10762 : *
10763 : * Only a few drivers will support this operation, and some of them might only
10764 : * support it only for some types of relationships.
10765 : * A dataset having at least some support for this
10766 : * operation should report the GDsCUpdateRelationship dataset capability.
10767 : *
10768 : * Anticipated failures will not be emitted through the CPLError()
10769 : * infrastructure, but will be reported in the failureReason output parameter.
10770 : *
10771 : * @param hDS Dataset handle.
10772 : * @param hRelationship The relationship definition. Contrary to the C++
10773 : * version, the passed object is copied.
10774 : * @param ppszFailureReason Output parameter. Will contain an error message if
10775 : * an error occurs (*ppszFailureReason to be freed
10776 : * with CPLFree). May be NULL.
10777 : * @return true in case of success.
10778 : * @since GDAL 3.5
10779 : */
10780 11 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10781 : GDALRelationshipH hRelationship,
10782 : char **ppszFailureReason)
10783 : {
10784 11 : VALIDATE_POINTER1(hDS, __func__, false);
10785 11 : VALIDATE_POINTER1(hRelationship, __func__, false);
10786 : std::unique_ptr<GDALRelationship> poRelationship(
10787 22 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10788 11 : std::string failureReason;
10789 22 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10790 11 : std::move(poRelationship), failureReason);
10791 11 : if (ppszFailureReason)
10792 : {
10793 0 : *ppszFailureReason =
10794 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10795 : }
10796 11 : return bRet;
10797 : }
10798 :
10799 : /************************************************************************/
10800 : /* GDALDatasetSetQueryLoggerFunc() */
10801 : /************************************************************************/
10802 :
10803 : /**
10804 : * Sets the SQL query logger callback.
10805 : *
10806 : * When supported by the driver, the callback will be called with
10807 : * the executed SQL text, the error message, the execution time in milliseconds,
10808 : * the number of records fetched/affected and the client status data.
10809 : *
10810 : * A value of -1 in the execution time or in the number of records indicates
10811 : * that the values are unknown.
10812 : *
10813 : * @param hDS Dataset handle.
10814 : * @param pfnQueryLoggerFunc Callback function
10815 : * @param poQueryLoggerArg Opaque client status data
10816 : * @return true in case of success.
10817 : * @since GDAL 3.7
10818 : */
10819 1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10820 : GDALQueryLoggerFunc pfnQueryLoggerFunc,
10821 : void *poQueryLoggerArg)
10822 : {
10823 1 : VALIDATE_POINTER1(hDS, __func__, false);
10824 2 : return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10825 1 : poQueryLoggerArg);
10826 : }
10827 :
10828 : //! @cond Doxygen_Suppress
10829 :
10830 : /************************************************************************/
10831 : /* SetEnableOverviews() */
10832 : /************************************************************************/
10833 :
10834 7545 : void GDALDataset::SetEnableOverviews(bool bEnable)
10835 : {
10836 7545 : if (m_poPrivate)
10837 : {
10838 7545 : m_poPrivate->m_bOverviewsEnabled = bEnable;
10839 : }
10840 7545 : }
10841 :
10842 : /************************************************************************/
10843 : /* AreOverviewsEnabled() */
10844 : /************************************************************************/
10845 :
10846 2012340 : bool GDALDataset::AreOverviewsEnabled() const
10847 : {
10848 2012340 : return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10849 : }
10850 :
10851 : /************************************************************************/
10852 : /* IsAllBands() */
10853 : /************************************************************************/
10854 :
10855 4252 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10856 : {
10857 4252 : if (nBands != nBandCount)
10858 21 : return false;
10859 4231 : if (panBandList)
10860 : {
10861 16033 : for (int i = 0; i < nBandCount; ++i)
10862 : {
10863 11896 : if (panBandList[i] != i + 1)
10864 27 : return false;
10865 : }
10866 : }
10867 4204 : return true;
10868 : }
10869 :
10870 : //! @endcond
10871 :
10872 : /************************************************************************/
10873 : /* GetCompressionFormats() */
10874 : /************************************************************************/
10875 :
10876 : /** Return the compression formats that can be natively obtained for the
10877 : * window of interest and requested bands.
10878 : *
10879 : * For example, a tiled dataset may be able to return data in a compressed
10880 : * format if the window of interest matches exactly a tile. For some formats,
10881 : * drivers may also be able to merge several tiles together (not currently
10882 : * implemented though).
10883 : *
10884 : * Each format string is a pseudo MIME type, whose first part can be passed
10885 : * as the pszFormat argument of ReadCompressedData(), with additional
10886 : * parameters specified as key=value with a semi-colon separator.
10887 : *
10888 : * The amount and types of optional parameters passed after the MIME type is
10889 : * format dependent, and driver dependent (some drivers might not be able to
10890 : * return those extra information without doing a rather costly processing).
10891 : *
10892 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10893 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10894 : * consequently "JPEG" can be passed as the pszFormat argument of
10895 : * ReadCompressedData(). For JPEG, implementations can use the
10896 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10897 : * above from a JPEG codestream.
10898 : *
10899 : * Several values might be returned. For example,
10900 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10901 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10902 : *
10903 : * In the general case this method will return an empty list.
10904 : *
10905 : * This is the same as C function GDALDatasetGetCompressionFormats().
10906 : *
10907 : * @param nXOff The pixel offset to the top left corner of the region
10908 : * of the band to be accessed. This would be zero to start from the left side.
10909 : *
10910 : * @param nYOff The line offset to the top left corner of the region
10911 : * of the band to be accessed. This would be zero to start from the top.
10912 : *
10913 : * @param nXSize The width of the region of the band to be accessed in pixels.
10914 : *
10915 : * @param nYSize The height of the region of the band to be accessed in lines.
10916 : *
10917 : * @param nBandCount the number of bands being requested.
10918 : *
10919 : * @param panBandList the list of nBandCount band numbers.
10920 : * Note band numbers are 1 based. This may be NULL to select the first
10921 : * nBandCount bands.
10922 : *
10923 : * @return a list of compatible formats (which may be empty)
10924 : *
10925 : * For example, to check if native compression format(s) are available on the
10926 : * whole image:
10927 : * \code{.cpp}
10928 : * const CPLStringList aosFormats =
10929 : * poDataset->GetCompressionFormats(0, 0,
10930 : * poDataset->GetRasterXSize(),
10931 : * poDataset->GetRasterYSize(),
10932 : * poDataset->GetRasterCount(),
10933 : * nullptr);
10934 : * for( const char* pszFormat: aosFormats )
10935 : * {
10936 : * // Remove optional parameters and just print out the MIME type.
10937 : * const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10938 : * printf("Found format %s\n, aosTokens[0]);
10939 : * }
10940 : * \endcode
10941 : *
10942 : * @since GDAL 3.7
10943 : */
10944 : CPLStringList
10945 0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10946 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10947 : CPL_UNUSED int nBandCount,
10948 : CPL_UNUSED const int *panBandList)
10949 : {
10950 0 : return CPLStringList();
10951 : }
10952 :
10953 : /************************************************************************/
10954 : /* GDALDatasetGetCompressionFormats() */
10955 : /************************************************************************/
10956 :
10957 : /** Return the compression formats that can be natively obtained for the
10958 : * window of interest and requested bands.
10959 : *
10960 : * For example, a tiled dataset may be able to return data in a compressed
10961 : * format if the window of interest matches exactly a tile. For some formats,
10962 : * drivers may also be able to merge several tiles together (not currently
10963 : * implemented though).
10964 : *
10965 : * Each format string is a pseudo MIME type, whose first part can be passed
10966 : * as the pszFormat argument of ReadCompressedData(), with additional
10967 : * parameters specified as key=value with a semi-colon separator.
10968 : *
10969 : * The amount and types of optional parameters passed after the MIME type is
10970 : * format dependent, and driver dependent (some drivers might not be able to
10971 : * return those extra information without doing a rather costly processing).
10972 : *
10973 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10974 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10975 : * consequently "JPEG" can be passed as the pszFormat argument of
10976 : * ReadCompressedData(). For JPEG, implementations can use the
10977 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10978 : * above from a JPEG codestream.
10979 : *
10980 : * Several values might be returned. For example,
10981 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10982 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10983 : *
10984 : * In the general case this method will return an empty list.
10985 : *
10986 : * This is the same as C++ method GDALDataset::GetCompressionFormats().
10987 : *
10988 : * @param hDS Dataset handle.
10989 : *
10990 : * @param nXOff The pixel offset to the top left corner of the region
10991 : * of the band to be accessed. This would be zero to start from the left side.
10992 : *
10993 : * @param nYOff The line offset to the top left corner of the region
10994 : * of the band to be accessed. This would be zero to start from the top.
10995 : *
10996 : * @param nXSize The width of the region of the band to be accessed in pixels.
10997 : *
10998 : * @param nYSize The height of the region of the band to be accessed in lines.
10999 : *
11000 : * @param nBandCount the number of bands being requested.
11001 : *
11002 : * @param panBandList the list of nBandCount band numbers.
11003 : * Note band numbers are 1 based. This may be NULL to select the first
11004 : * nBandCount bands.
11005 : *
11006 : * @return a list of compatible formats (which may be empty) that should be
11007 : * freed with CSLDestroy(), or nullptr.
11008 : *
11009 : * @since GDAL 3.7
11010 : */
11011 9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
11012 : int nXSize, int nYSize, int nBandCount,
11013 : const int *panBandList)
11014 : {
11015 9 : VALIDATE_POINTER1(hDS, __func__, nullptr);
11016 9 : return GDALDataset::FromHandle(hDS)
11017 9 : ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
11018 9 : panBandList)
11019 9 : .StealList();
11020 : }
11021 :
11022 : /************************************************************************/
11023 : /* ReadCompressedData() */
11024 : /************************************************************************/
11025 :
11026 : /** Return the compressed content that can be natively obtained for the
11027 : * window of interest and requested bands.
11028 : *
11029 : * For example, a tiled dataset may be able to return data in compressed format
11030 : * if the window of interest matches exactly a tile. For some formats, drivers
11031 : * may also be example to merge several tiles together (not currently
11032 : * implemented though).
11033 : *
11034 : * The implementation should make sure that the content returned forms a valid
11035 : * standalone file. For example, for the GeoTIFF implementation of this method,
11036 : * when extracting a JPEG tile, the method will automatically add the content
11037 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11038 : * TIFF JpegTables tag, and not in tile data itself.
11039 : *
11040 : * In the general case this method will return CE_Failure.
11041 : *
11042 : * This is the same as C function GDALDatasetReadCompressedData().
11043 : *
11044 : * @param pszFormat Requested compression format (e.g. "JPEG",
11045 : * "WEBP", "JXL"). This is the MIME type of one of the values
11046 : * returned by GetCompressionFormats(). The format string is designed to
11047 : * potentially include at a later point key=value optional parameters separated
11048 : * by a semi-colon character. At time of writing, none are implemented.
11049 : * ReadCompressedData() implementations should verify optional parameters and
11050 : * return CE_Failure if they cannot support one of them.
11051 : *
11052 : * @param nXOff The pixel offset to the top left corner of the region
11053 : * of the band to be accessed. This would be zero to start from the left side.
11054 : *
11055 : * @param nYOff The line offset to the top left corner of the region
11056 : * of the band to be accessed. This would be zero to start from the top.
11057 : *
11058 : * @param nXSize The width of the region of the band to be accessed in pixels.
11059 : *
11060 : * @param nYSize The height of the region of the band to be accessed in lines.
11061 : *
11062 : * @param nBandCount the number of bands being requested.
11063 : *
11064 : * @param panBandList the list of nBandCount band numbers.
11065 : * Note band numbers are 1 based. This may be NULL to select the first
11066 : * nBandCount bands.
11067 : *
11068 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11069 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11070 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11071 : * buffer will be filled with the compressed data, provided that pnBufferSize
11072 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11073 : * of *ppBuffer, is sufficiently large to hold the data.
11074 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11075 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11076 : * free it with VSIFree().
11077 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11078 : * but *pnBufferSize will be updated with an upper bound of the size that would
11079 : * be necessary to hold it (if pnBufferSize != nullptr).
11080 : *
11081 : * @param pnBufferSize Output buffer size, or nullptr.
11082 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11083 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11084 : * method is successful, *pnBufferSize will be updated with the actual size
11085 : * used.
11086 : *
11087 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11088 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11089 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11090 : * *ppszDetailedFormat might contain strings like
11091 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11092 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11093 : * The string will contain at least as much information as what
11094 : * GetCompressionFormats() returns, and potentially more when
11095 : * ppBuffer != nullptr.
11096 : *
11097 : * @return CE_None in case of success, CE_Failure otherwise.
11098 : *
11099 : * For example, to request JPEG content on the whole image and let GDAL deal
11100 : * with the buffer allocation.
11101 : * \code{.cpp}
11102 : * void* pBuffer = nullptr;
11103 : * size_t nBufferSize = 0;
11104 : * CPLErr eErr =
11105 : * poDataset->ReadCompressedData("JPEG",
11106 : * 0, 0,
11107 : * poDataset->GetRasterXSize(),
11108 : * poDataset->GetRasterYSize(),
11109 : * poDataset->GetRasterCount(),
11110 : * nullptr, // panBandList
11111 : * &pBuffer,
11112 : * &nBufferSize,
11113 : * nullptr // ppszDetailedFormat
11114 : * );
11115 : * if (eErr == CE_None)
11116 : * {
11117 : * CPLAssert(pBuffer != nullptr);
11118 : * CPLAssert(nBufferSize > 0);
11119 : * VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11120 : * if (fp)
11121 : * {
11122 : * VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11123 : * VSIFCloseL(fp);
11124 : * }
11125 : * VSIFree(pBuffer);
11126 : * }
11127 : * \endcode
11128 : *
11129 : * Or to manage the buffer allocation on your side:
11130 : * \code{.cpp}
11131 : * size_t nUpperBoundBufferSize = 0;
11132 : * CPLErr eErr =
11133 : * poDataset->ReadCompressedData("JPEG",
11134 : * 0, 0,
11135 : * poDataset->GetRasterXSize(),
11136 : * poDataset->GetRasterYSize(),
11137 : * poDataset->GetRasterCount(),
11138 : * nullptr, // panBandList
11139 : * nullptr, // ppBuffer,
11140 : * &nUpperBoundBufferSize,
11141 : * nullptr // ppszDetailedFormat
11142 : * );
11143 : * if (eErr == CE_None)
11144 : * {
11145 : * std::vector<uint8_t> myBuffer;
11146 : * myBuffer.resize(nUpperBoundBufferSize);
11147 : * void* pBuffer = myBuffer.data();
11148 : * size_t nActualSize = nUpperBoundBufferSize;
11149 : * char* pszDetailedFormat = nullptr;
11150 : * // We also request detailed format, but we could have passed it to
11151 : * // nullptr as well.
11152 : * eErr =
11153 : * poDataset->ReadCompressedData("JPEG",
11154 : * 0, 0,
11155 : * poDataset->GetRasterXSize(),
11156 : * poDataset->GetRasterYSize(),
11157 : * poDataset->GetRasterCount(),
11158 : * nullptr, // panBandList
11159 : * &pBuffer,
11160 : * &nActualSize,
11161 : * &pszDetailedFormat);
11162 : * if (eErr == CE_None)
11163 : * {
11164 : * CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11165 : * CPLAssert(nActualSize <= nUpperBoundBufferSize);
11166 : * myBuffer.resize(nActualSize);
11167 : * // do something useful
11168 : * VSIFree(pszDetailedFormat);
11169 : * }
11170 : * }
11171 : * \endcode
11172 : *
11173 : * @since GDAL 3.7
11174 : */
11175 450 : CPLErr GDALDataset::ReadCompressedData(
11176 : CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11177 : CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11178 : CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11179 : CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11180 : CPL_UNUSED char **ppszDetailedFormat)
11181 : {
11182 450 : return CE_Failure;
11183 : }
11184 :
11185 : /************************************************************************/
11186 : /* GDALDatasetReadCompressedData() */
11187 : /************************************************************************/
11188 :
11189 : /** Return the compressed content that can be natively obtained for the
11190 : * window of interest and requested bands.
11191 : *
11192 : * For example, a tiled dataset may be able to return data in compressed format
11193 : * if the window of interest matches exactly a tile. For some formats, drivers
11194 : * may also be example to merge several tiles together (not currently
11195 : * implemented though).
11196 : *
11197 : * The implementation should make sure that the content returned forms a valid
11198 : * standalone file. For example, for the GeoTIFF implementation of this method,
11199 : * when extracting a JPEG tile, the method will automatically adds the content
11200 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11201 : * TIFF JpegTables tag, and not in tile data itself.
11202 : *
11203 : * In the general case this method will return CE_Failure.
11204 : *
11205 : * This is the same as C++ method GDALDataset:ReadCompressedData().
11206 : *
11207 : * @param hDS Dataset handle.
11208 : *
11209 : * @param pszFormat Requested compression format (e.g. "JPEG",
11210 : * "WEBP", "JXL"). This is the MIME type of one of the values
11211 : * returned by GetCompressionFormats(). The format string is designed to
11212 : * potentially include at a later point key=value optional parameters separated
11213 : * by a semi-colon character. At time of writing, none are implemented.
11214 : * ReadCompressedData() implementations should verify optional parameters and
11215 : * return CE_Failure if they cannot support one of them.
11216 : *
11217 : * @param nXOff The pixel offset to the top left corner of the region
11218 : * of the band to be accessed. This would be zero to start from the left side.
11219 : *
11220 : * @param nYOff The line offset to the top left corner of the region
11221 : * of the band to be accessed. This would be zero to start from the top.
11222 : *
11223 : * @param nXSize The width of the region of the band to be accessed in pixels.
11224 : *
11225 : * @param nYSize The height of the region of the band to be accessed in lines.
11226 : *
11227 : * @param nBandCount the number of bands being requested.
11228 : *
11229 : * @param panBandList the list of nBandCount band numbers.
11230 : * Note band numbers are 1 based. This may be NULL to select the first
11231 : * nBandCount bands.
11232 : *
11233 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11234 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11235 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11236 : * buffer will be filled with the compressed data, provided that pnBufferSize
11237 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11238 : * of *ppBuffer, is sufficiently large to hold the data.
11239 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11240 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11241 : * free it with VSIFree().
11242 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11243 : * but *pnBufferSize will be updated with an upper bound of the size that would
11244 : * be necessary to hold it (if pnBufferSize != nullptr).
11245 : *
11246 : * @param pnBufferSize Output buffer size, or nullptr.
11247 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11248 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11249 : * method is successful, *pnBufferSize will be updated with the actual size
11250 : * used.
11251 : *
11252 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11253 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11254 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11255 : * *ppszDetailedFormat might contain strings like
11256 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11257 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11258 : * The string will contain at least as much information as what
11259 : * GetCompressionFormats() returns, and potentially more when
11260 : * ppBuffer != nullptr.
11261 : *
11262 : * @return CE_None in case of success, CE_Failure otherwise.
11263 : *
11264 : * @since GDAL 3.7
11265 : */
11266 28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11267 : int nXOff, int nYOff, int nXSize,
11268 : int nYSize, int nBandCount,
11269 : const int *panBandList, void **ppBuffer,
11270 : size_t *pnBufferSize,
11271 : char **ppszDetailedFormat)
11272 : {
11273 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11274 56 : return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11275 : pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11276 28 : ppBuffer, pnBufferSize, ppszDetailedFormat);
11277 : }
11278 :
11279 : /************************************************************************/
11280 : /* CanBeCloned() */
11281 : /************************************************************************/
11282 :
11283 : //! @cond Doxygen_Suppress
11284 :
11285 : /** This method is called by GDALThreadSafeDataset::Create() to determine if
11286 : * it is possible to create a thread-safe wrapper for a dataset, which involves
11287 : * the ability to Clone() it.
11288 : *
11289 : * Implementations of this method must be thread-safe.
11290 : *
11291 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11292 : * expressing the intended use for thread-safety.
11293 : * Currently, the only valid scope is in the base
11294 : * implementation is GDAL_OF_RASTER.
11295 : * @param bCanShareState Determines if cloned datasets are allowed to share
11296 : * state with the dataset they have been cloned from.
11297 : * If set to true, the dataset from which they have been
11298 : * cloned from must remain opened during the lifetime of
11299 : * its clones.
11300 : * @return true if the Clone() method is expected to succeed with the same values
11301 : * of nScopeFlags and bCanShareState.
11302 : */
11303 151 : bool GDALDataset::CanBeCloned(int nScopeFlags,
11304 : [[maybe_unused]] bool bCanShareState) const
11305 : {
11306 151 : return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11307 : }
11308 :
11309 : //! @endcond
11310 :
11311 : /************************************************************************/
11312 : /* Clone() */
11313 : /************************************************************************/
11314 :
11315 : //! @cond Doxygen_Suppress
11316 :
11317 : /** This method "clones" the current dataset, that is it returns a new instance
11318 : * that is opened on the same underlying "file".
11319 : *
11320 : * The base implementation uses GDALDataset::Open() to re-open the dataset.
11321 : * The MEM driver has a specialized implementation that returns a new instance,
11322 : * but which shares the same memory buffer as this.
11323 : *
11324 : * Implementations of this method must be thread-safe.
11325 : *
11326 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11327 : * expressing the intended use for thread-safety.
11328 : * Currently, the only valid scope is in the base
11329 : * implementation is GDAL_OF_RASTER.
11330 : * @param bCanShareState Determines if cloned datasets are allowed to share
11331 : * state with the dataset they have been cloned from.
11332 : * If set to true, the dataset from which they have been
11333 : * cloned from must remain opened during the lifetime of
11334 : * its clones.
11335 : * @return a new instance, or nullptr in case of error.
11336 : */
11337 : std::unique_ptr<GDALDataset>
11338 2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11339 : {
11340 4102 : CPLStringList aosAllowedDrivers;
11341 2051 : if (poDriver)
11342 2051 : aosAllowedDrivers.AddString(poDriver->GetDescription());
11343 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11344 2051 : GetDescription(),
11345 2051 : nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11346 4102 : aosAllowedDrivers.List(), papszOpenOptions));
11347 : }
11348 :
11349 : //! @endcond
11350 :
11351 : /************************************************************************/
11352 : /* GeolocationToPixelLine() */
11353 : /************************************************************************/
11354 :
11355 : /** Transform georeferenced coordinates to pixel/line coordinates.
11356 : *
11357 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11358 : * must be in the "natural" SRS of the dataset, that is the one returned by
11359 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11360 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11361 : * array (generally WGS 84) if there is a geolocation array.
11362 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11363 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11364 : * be a easting, and dfGeolocY a northing.
11365 : *
11366 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11367 : * expressed in that CRS, and that tuple must be conformant with the
11368 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11369 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11370 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11371 : * before calling this method, and in that case, dfGeolocX must be a longitude
11372 : * or an easting value, and dfGeolocX a latitude or a northing value.
11373 : *
11374 : * This method uses GDALCreateGenImgProjTransformer2() underneath.
11375 : *
11376 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11377 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11378 : * where interpolation should be done.
11379 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11380 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11381 : * where interpolation should be done.
11382 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11383 : * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11384 : * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11385 : * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11386 : *
11387 : * @return CE_None on success, or an error code on failure.
11388 : * @since GDAL 3.11
11389 : */
11390 :
11391 : CPLErr
11392 15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11393 : const OGRSpatialReference *poSRS,
11394 : double *pdfPixel, double *pdfLine,
11395 : CSLConstList papszTransformerOptions) const
11396 : {
11397 30 : CPLStringList aosTO(papszTransformerOptions);
11398 :
11399 15 : if (poSRS)
11400 : {
11401 4 : const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11402 8 : const std::string osWKT = poSRS->exportToWkt(apszOptions);
11403 4 : aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11404 4 : const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11405 4 : if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11406 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11407 1 : "TRADITIONAL_GIS_ORDER");
11408 3 : else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11409 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11410 1 : "AUTHORITY_COMPLIANT");
11411 : else
11412 : {
11413 2 : const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11414 4 : std::string osVal;
11415 6 : for (int v : anValues)
11416 : {
11417 4 : if (!osVal.empty())
11418 2 : osVal += ',';
11419 4 : osVal += std::to_string(v);
11420 : }
11421 : aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11422 2 : osVal.c_str());
11423 : }
11424 : }
11425 :
11426 15 : auto hTransformer = GDALCreateGenImgProjTransformer2(
11427 : GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11428 15 : aosTO.List());
11429 15 : if (hTransformer == nullptr)
11430 : {
11431 1 : return CE_Failure;
11432 : }
11433 :
11434 14 : double z = 0;
11435 14 : int bSuccess = 0;
11436 14 : GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11437 : &bSuccess);
11438 14 : GDALDestroyTransformer(hTransformer);
11439 14 : if (bSuccess)
11440 : {
11441 14 : if (pdfPixel)
11442 14 : *pdfPixel = dfGeolocX;
11443 14 : if (pdfLine)
11444 14 : *pdfLine = dfGeolocY;
11445 14 : return CE_None;
11446 : }
11447 : else
11448 : {
11449 0 : return CE_Failure;
11450 : }
11451 : }
11452 :
11453 : /************************************************************************/
11454 : /* GDALDatasetGeolocationToPixelLine() */
11455 : /************************************************************************/
11456 :
11457 : /** Transform georeferenced coordinates to pixel/line coordinates.
11458 : *
11459 : * @see GDALDataset::GeolocationToPixelLine()
11460 : * @since GDAL 3.11
11461 : */
11462 :
11463 0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11464 : double dfGeolocY,
11465 : OGRSpatialReferenceH hSRS,
11466 : double *pdfPixel, double *pdfLine,
11467 : CSLConstList papszTransformerOptions)
11468 : {
11469 0 : VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11470 :
11471 0 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11472 0 : return poDS->GeolocationToPixelLine(
11473 0 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11474 0 : pdfLine, papszTransformerOptions);
11475 : }
11476 :
11477 : /************************************************************************/
11478 : /* GetExtent() */
11479 : /************************************************************************/
11480 :
11481 : /** Return extent of dataset in specified CRS.
11482 : *
11483 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11484 : *
11485 : * For rasters, the base implementation of this method only succeeds if
11486 : * GetGeoTransform() and GetSpatialRef() succeed.
11487 : * For vectors, the base implementation of this method iterates over layers
11488 : * and call their OGRLayer::GetExtent() method.
11489 : *
11490 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11491 : * time of this method is fast.
11492 : *
11493 : * This is the same as C function GDALGetExtent()
11494 : *
11495 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11496 : * @param poCRS CRS in which to express the extent. If not specified, this will
11497 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11498 : * @return CE_None in case of success, CE_Failure otherwise
11499 : * @since GDAL 3.12
11500 : */
11501 :
11502 476 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11503 : const OGRSpatialReference *poCRS) const
11504 : {
11505 476 : const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11506 476 : int nLayerCount = 0;
11507 476 : if (!poThisCRS)
11508 : {
11509 93 : nLayerCount = GetLayerCount();
11510 93 : if (nLayerCount >= 1)
11511 : {
11512 3 : if (auto poLayer = GetLayer(0))
11513 3 : poThisCRS = poLayer->GetSpatialRef();
11514 : }
11515 : }
11516 476 : if (!poCRS)
11517 254 : poCRS = poThisCRS;
11518 222 : else if (!poThisCRS)
11519 3 : return CE_Failure;
11520 :
11521 473 : *psExtent = OGREnvelope();
11522 :
11523 473 : GDALGeoTransform gt;
11524 473 : auto poThisDS = const_cast<GDALDataset *>(this);
11525 473 : const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11526 473 : if (bHasGT)
11527 : {
11528 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
11529 468 : if (poCRS)
11530 : {
11531 383 : poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11532 : }
11533 :
11534 468 : constexpr int DENSIFY_POINT_COUNT = 21;
11535 468 : double dfULX = gt.xorig;
11536 468 : double dfULY = gt.yorig;
11537 468 : double dfURX = 0, dfURY = 0;
11538 468 : gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11539 468 : double dfLLX = 0, dfLLY = 0;
11540 468 : gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11541 468 : double dfLRX = 0, dfLRY = 0;
11542 468 : gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11543 468 : const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11544 468 : const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11545 468 : const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11546 468 : const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11547 468 : if (poCT)
11548 : {
11549 381 : OGREnvelope sEnvTmp;
11550 762 : if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11551 : &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11552 381 : &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11553 : {
11554 0 : return CE_Failure;
11555 : }
11556 381 : *psExtent = sEnvTmp;
11557 : }
11558 : else
11559 : {
11560 87 : psExtent->MinX = xmin;
11561 87 : psExtent->MinY = ymin;
11562 87 : psExtent->MaxX = xmax;
11563 87 : psExtent->MaxY = ymax;
11564 : }
11565 : }
11566 :
11567 473 : if (nLayerCount > 0)
11568 : {
11569 6 : for (auto &&poLayer : poThisDS->GetLayers())
11570 : {
11571 3 : auto poLayerCRS = poLayer->GetSpatialRef();
11572 3 : if (poLayerCRS)
11573 : {
11574 3 : OGREnvelope sLayerExtent;
11575 3 : if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11576 : {
11577 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11578 6 : OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11579 3 : if (poCT)
11580 : {
11581 3 : constexpr int DENSIFY_POINT_COUNT = 21;
11582 3 : OGREnvelope sEnvTmp;
11583 3 : if (poCT->TransformBounds(
11584 : sLayerExtent.MinX, sLayerExtent.MinY,
11585 : sLayerExtent.MaxX, sLayerExtent.MaxY,
11586 : &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11587 : &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11588 3 : DENSIFY_POINT_COUNT))
11589 : {
11590 3 : psExtent->Merge(sEnvTmp);
11591 : }
11592 : }
11593 : }
11594 : }
11595 : }
11596 : }
11597 :
11598 473 : return psExtent->IsInit() ? CE_None : CE_Failure;
11599 : }
11600 :
11601 : /************************************************************************/
11602 : /* GDALGetExtent() */
11603 : /************************************************************************/
11604 :
11605 : /** Return extent of dataset in specified CRS.
11606 : *
11607 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11608 : *
11609 : * For rasters, the base implementation of this method only succeeds if
11610 : * GetGeoTransform() and GetSpatialRef() succeed.
11611 : * For vectors, the base implementation of this method iterates over layers
11612 : * and call their OGRLayer::GetExtent() method.
11613 : *
11614 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11615 : * time of this method is fast.
11616 : *
11617 : * This is the same as C++ method GDALDataset::GetExtent()
11618 : *
11619 : * @param hDS Dataset handle. Must NOT be null.
11620 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11621 : * @param hCRS CRS in which to express the extent. If not specified, this will
11622 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11623 : * @return extent in poCRS (valid only if IsInit() method returns true)
11624 : * @since GDAL 3.12
11625 : */
11626 :
11627 28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11628 : OGRSpatialReferenceH hCRS)
11629 : {
11630 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11631 28 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11632 56 : return GDALDataset::FromHandle(hDS)->GetExtent(
11633 28 : psExtent, OGRSpatialReference::FromHandle(hCRS));
11634 : }
11635 :
11636 : /************************************************************************/
11637 : /* GetExtentWGS84LongLat() */
11638 : /************************************************************************/
11639 :
11640 : /** Return extent of dataset in WGS84 longitude/latitude
11641 : *
11642 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11643 : *
11644 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11645 : * time of this method is fast.
11646 : *
11647 : * This is the same as C function GDALGetExtentWGS84LongLat()
11648 : *
11649 : * @return extent (valid only if IsInit() method returns true)
11650 : * @since GDAL 3.12
11651 : */
11652 :
11653 220 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11654 : {
11655 440 : OGRSpatialReference oSRS_WGS84;
11656 220 : oSRS_WGS84.SetFromUserInput("WGS84");
11657 220 : oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11658 440 : return GetExtent(psExtent, &oSRS_WGS84);
11659 : }
11660 :
11661 : /************************************************************************/
11662 : /* GDALGetExtentWGS84LongLat() */
11663 : /************************************************************************/
11664 :
11665 : /** Return extent of dataset in WGS84 longitude/latitude
11666 : *
11667 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11668 : *
11669 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11670 : * time of this method is fast.
11671 : *
11672 : * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11673 : *
11674 : * @param hDS Dataset handle. Must NOT be null.
11675 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11676 : * @return extent (valid only if IsInit() method returns true)
11677 : * @since GDAL 3.12
11678 : */
11679 :
11680 5 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11681 : {
11682 5 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11683 5 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11684 5 : return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11685 : }
11686 :
11687 : /************************************************************************/
11688 : /* ReportUpdateNotSupportedByDriver() */
11689 : /************************************************************************/
11690 :
11691 : //! @cond Doxygen_Suppress
11692 :
11693 : /* static */
11694 1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11695 : {
11696 1 : CPLError(CE_Failure, CPLE_NotSupported,
11697 : "The %s driver does not support update access to existing "
11698 : "datasets.",
11699 : pszDriverName);
11700 1 : }
11701 :
11702 : //! @endcond
11703 :
11704 : /************************************************************************/
11705 : /* BuildFilename() */
11706 : /************************************************************************/
11707 :
11708 : /** Generates a filename, potentially relative to another one.
11709 : *
11710 : * Given the path to a reference directory, and a path to a file
11711 : * referenced from it, build a path to the file that the current application
11712 : * can use. If the file path is already absolute, rather than relative, or if
11713 : * bRelativeToReferencePath is false, then the filename of interest will be
11714 : * returned unaltered.
11715 : *
11716 : * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11717 : * into account the subdataset syntax.
11718 : *
11719 : * Examples:
11720 : * \code{.cpp}
11721 : * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11722 : * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11723 : * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11724 : * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11725 : * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11726 : * \endcode
11727 : *
11728 : * @param pszFilename Filename of interest.
11729 : * @param pszReferencePath Path to a reference directory.
11730 : * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11731 : * relative to pszReferencePath
11732 : * @since 3.11
11733 : */
11734 :
11735 : /* static */
11736 104278 : std::string GDALDataset::BuildFilename(const char *pszFilename,
11737 : const char *pszReferencePath,
11738 : bool bRelativeToReferencePath)
11739 : {
11740 104278 : std::string osSrcDSName;
11741 104278 : if (pszReferencePath != nullptr && bRelativeToReferencePath)
11742 : {
11743 : // Try subdatasetinfo API first
11744 : // Note: this will become the only branch when subdatasetinfo will become
11745 : // available for NITF_IM, RASTERLITE and TILEDB
11746 2622 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11747 2622 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11748 : {
11749 8 : auto path{oSubDSInfo->GetPathComponent()};
11750 12 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
11751 8 : CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11752 4 : .c_str());
11753 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
11754 : }
11755 : else
11756 : {
11757 2618 : bool bDone = false;
11758 15693 : for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11759 : {
11760 13078 : CPLString osPrefix(pszSyntax);
11761 13078 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11762 13078 : if (pszSyntax[osPrefix.size()] == '"')
11763 2615 : osPrefix += '"';
11764 13078 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11765 : {
11766 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11767 : {
11768 3 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11769 : // CSV:z:/foo.xyz
11770 3 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11771 0 : pszLastPart - pszFilename >= 3 &&
11772 0 : pszLastPart[-3] == ':')
11773 : {
11774 0 : pszLastPart -= 2;
11775 : }
11776 3 : CPLString osPrefixFilename = pszFilename;
11777 3 : osPrefixFilename.resize(pszLastPart - pszFilename);
11778 6 : osSrcDSName = osPrefixFilename +
11779 6 : CPLProjectRelativeFilenameSafe(
11780 3 : pszReferencePath, pszLastPart);
11781 3 : bDone = true;
11782 : }
11783 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11784 : "{FILENAME}"))
11785 : {
11786 0 : CPLString osFilename(pszFilename + osPrefix.size());
11787 0 : size_t nPos = 0;
11788 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11789 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
11790 0 : nPos = 2;
11791 0 : nPos = osFilename.find(
11792 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11793 : nPos);
11794 0 : if (nPos != std::string::npos)
11795 : {
11796 0 : const CPLString osSuffix = osFilename.substr(nPos);
11797 0 : osFilename.resize(nPos);
11798 0 : osSrcDSName = osPrefix +
11799 0 : CPLProjectRelativeFilenameSafe(
11800 0 : pszReferencePath, osFilename) +
11801 0 : osSuffix;
11802 0 : bDone = true;
11803 : }
11804 : }
11805 3 : break;
11806 : }
11807 : }
11808 2618 : if (!bDone)
11809 : {
11810 2615 : std::string osReferencePath = pszReferencePath;
11811 2615 : if (!CPLIsFilenameRelative(pszReferencePath))
11812 : {
11813 : // Simplify path by replacing "foo/a/../b" with "foo/b"
11814 2322 : while (STARTS_WITH(pszFilename, "../"))
11815 : {
11816 : osReferencePath =
11817 5 : CPLGetPathSafe(osReferencePath.c_str());
11818 5 : pszFilename += strlen("../");
11819 : }
11820 : }
11821 :
11822 5230 : osSrcDSName = CPLProjectRelativeFilenameSafe(
11823 2615 : osReferencePath.c_str(), pszFilename);
11824 : }
11825 2622 : }
11826 : }
11827 : else
11828 : {
11829 101656 : osSrcDSName = pszFilename;
11830 : }
11831 104278 : return osSrcDSName;
11832 : }
11833 :
11834 : /************************************************************************/
11835 : /* GDALMDArrayFromDataset */
11836 : /************************************************************************/
11837 :
11838 : class GDALMDArrayFromDataset final : public GDALMDArray
11839 : {
11840 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11841 :
11842 : GDALDataset *const m_poDS;
11843 : const GDALExtendedDataType m_dt;
11844 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11845 : std::string m_osUnit{};
11846 : std::vector<GByte> m_abyNoData{};
11847 : std::shared_ptr<GDALMDArray> m_varX{};
11848 : std::shared_ptr<GDALMDArray> m_varY{};
11849 : std::shared_ptr<GDALMDArray> m_varBand{};
11850 : const std::string m_osFilename;
11851 : const CPLStringList m_aosOptions;
11852 : int m_iBandDim = 0;
11853 : int m_iYDim = 1;
11854 : int m_iXDim = 2;
11855 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11856 :
11857 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11858 : const size_t *count, const GInt64 *arrayStep,
11859 : const GPtrDiff_t *bufferStride,
11860 : const GDALExtendedDataType &bufferDataType,
11861 : void *pBuffer) const;
11862 :
11863 : protected:
11864 17 : GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11865 34 : : GDALAbstractMDArray(std::string(),
11866 34 : std::string(poDS->GetDescription())),
11867 34 : GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11868 : m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11869 : poDS->GetRasterBand(1)->GetRasterDataType())),
11870 85 : m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11871 : {
11872 17 : m_poDS->Reference();
11873 :
11874 17 : const int nBandCount = poDS->GetRasterCount();
11875 47 : for (int i = 1; i <= nBandCount; ++i)
11876 : {
11877 30 : const auto poBand = poDS->GetRasterBand(i);
11878 30 : if (i == 1)
11879 17 : m_osUnit = poBand->GetUnitType();
11880 13 : else if (m_osUnit != poBand->GetUnitType())
11881 7 : m_osUnit.clear();
11882 :
11883 60 : std::vector<GByte> abyNoData;
11884 30 : int bHasNoData = false;
11885 30 : switch (poBand->GetRasterDataType())
11886 : {
11887 0 : case GDT_Int64:
11888 : {
11889 : const auto nNoData =
11890 0 : poBand->GetNoDataValueAsInt64(&bHasNoData);
11891 0 : if (bHasNoData)
11892 : {
11893 0 : abyNoData.resize(m_dt.GetSize());
11894 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11895 : m_dt.GetNumericDataType(), 0, 1);
11896 : }
11897 0 : break;
11898 : }
11899 :
11900 0 : case GDT_UInt64:
11901 : {
11902 : const auto nNoData =
11903 0 : poBand->GetNoDataValueAsUInt64(&bHasNoData);
11904 0 : if (bHasNoData)
11905 : {
11906 0 : abyNoData.resize(m_dt.GetSize());
11907 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11908 : m_dt.GetNumericDataType(), 0, 1);
11909 : }
11910 0 : break;
11911 : }
11912 :
11913 30 : default:
11914 : {
11915 30 : const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11916 30 : if (bHasNoData)
11917 : {
11918 11 : abyNoData.resize(m_dt.GetSize());
11919 22 : GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11920 11 : &abyNoData[0],
11921 : m_dt.GetNumericDataType(), 0, 1);
11922 : }
11923 30 : break;
11924 : }
11925 : }
11926 :
11927 30 : if (i == 1)
11928 17 : m_abyNoData = std::move(abyNoData);
11929 13 : else if (m_abyNoData != abyNoData)
11930 7 : m_abyNoData.clear();
11931 : }
11932 :
11933 17 : const int nXSize = poDS->GetRasterXSize();
11934 17 : const int nYSize = poDS->GetRasterYSize();
11935 :
11936 17 : auto poSRS = poDS->GetSpatialRef();
11937 34 : std::string osTypeY;
11938 34 : std::string osTypeX;
11939 34 : std::string osDirectionY;
11940 34 : std::string osDirectionX;
11941 17 : if (poSRS && poSRS->GetAxesCount() == 2)
11942 : {
11943 8 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11944 8 : OGRAxisOrientation eOrientation1 = OAO_Other;
11945 8 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11946 8 : OGRAxisOrientation eOrientation2 = OAO_Other;
11947 8 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11948 8 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11949 : {
11950 6 : if (mapping == std::vector<int>{1, 2})
11951 : {
11952 6 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11953 6 : osDirectionY = "NORTH";
11954 6 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11955 6 : osDirectionX = "EAST";
11956 : }
11957 : }
11958 2 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11959 : {
11960 2 : if (mapping == std::vector<int>{2, 1})
11961 : {
11962 2 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11963 2 : osDirectionY = "NORTH";
11964 2 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11965 2 : osDirectionX = "EAST";
11966 : }
11967 : }
11968 : }
11969 :
11970 47 : const bool bBandYX = [papszOptions, poDS, nBandCount]()
11971 : {
11972 : const char *pszDimOrder =
11973 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11974 17 : if (EQUAL(pszDimOrder, "AUTO"))
11975 : {
11976 30 : const char *pszInterleave = poDS->GetMetadataItem(
11977 15 : GDALMD_INTERLEAVE, GDAL_MDD_IMAGE_STRUCTURE);
11978 24 : return nBandCount == 1 || !pszInterleave ||
11979 24 : !EQUAL(pszInterleave, "PIXEL");
11980 : }
11981 : else
11982 : {
11983 2 : return EQUAL(pszDimOrder, "BAND,Y,X");
11984 : }
11985 17 : }();
11986 : const char *const pszBandDimName =
11987 17 : CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11988 : auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11989 51 : "/", pszBandDimName, std::string(), std::string(), nBandCount);
11990 : const char *const pszYDimName =
11991 17 : CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11992 : auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11993 34 : "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11994 : const char *const pszXDimName =
11995 17 : CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11996 : auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11997 34 : "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11998 :
11999 17 : const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
12000 : papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
12001 17 : if (EQUAL(pszBandIndexingVarItem, "{Description}"))
12002 : {
12003 : const auto oIndexingVarType =
12004 22 : GDALExtendedDataType::CreateString(strlen("Band 65535"));
12005 11 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12006 44 : {poBandDim}, oIndexingVarType);
12007 11 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12008 29 : for (int i = 0; i < nBandCount; ++i)
12009 : {
12010 : const char *pszDesc =
12011 18 : poDS->GetRasterBand(i + 1)->GetDescription();
12012 : const std::string osBandName =
12013 36 : pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
12014 18 : const char *pszBandName = osBandName.c_str();
12015 18 : const char *const apszBandVal[] = {pszBandName};
12016 18 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12017 18 : const size_t anCount[] = {1};
12018 18 : const GInt64 arrayStep[] = {1};
12019 18 : const GPtrDiff_t anBufferStride[] = {1};
12020 18 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12021 : oIndexingVarType, apszBandVal);
12022 : }
12023 11 : m_varBand = std::move(poBandVar);
12024 11 : poBandDim->SetIndexingVariable(m_varBand);
12025 : }
12026 6 : else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
12027 : {
12028 : const auto oIndexingVarType =
12029 2 : GDALExtendedDataType::Create(GDT_Int32);
12030 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12031 4 : {poBandDim}, oIndexingVarType);
12032 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12033 3 : for (int i = 0; i < nBandCount; ++i)
12034 : {
12035 2 : const int anBandIdx[] = {i + 1};
12036 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12037 2 : const size_t anCount[] = {1};
12038 2 : const GInt64 arrayStep[] = {1};
12039 2 : const GPtrDiff_t anBufferStride[] = {1};
12040 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12041 : oIndexingVarType, anBandIdx);
12042 : }
12043 1 : m_varBand = std::move(poBandVar);
12044 1 : poBandDim->SetIndexingVariable(m_varBand);
12045 : }
12046 5 : else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
12047 : {
12048 1 : size_t nMaxLen = 0;
12049 3 : for (int i = 0; i < nBandCount; ++i)
12050 : {
12051 2 : const char *pszDesc = GDALGetColorInterpretationName(
12052 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12053 2 : nMaxLen = std::max(nMaxLen, strlen(pszDesc));
12054 : }
12055 : const auto oIndexingVarType =
12056 2 : GDALExtendedDataType::CreateString(nMaxLen);
12057 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12058 4 : {poBandDim}, oIndexingVarType);
12059 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12060 3 : for (int i = 0; i < nBandCount; ++i)
12061 : {
12062 2 : const char *pszDesc = GDALGetColorInterpretationName(
12063 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12064 2 : const char *const apszBandVal[] = {pszDesc};
12065 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12066 2 : const size_t anCount[] = {1};
12067 2 : const GInt64 arrayStep[] = {1};
12068 2 : const GPtrDiff_t anBufferStride[] = {1};
12069 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12070 : oIndexingVarType, apszBandVal);
12071 : }
12072 1 : m_varBand = std::move(poBandVar);
12073 1 : poBandDim->SetIndexingVariable(m_varBand);
12074 : }
12075 4 : else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
12076 : {
12077 3 : const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
12078 : papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
12079 3 : size_t nMaxLen = 0;
12080 3 : if (EQUAL(pszBandIndexingVarType, "String"))
12081 : {
12082 3 : for (int i = 0; i < nBandCount; ++i)
12083 : {
12084 : const char *pszVal =
12085 2 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
12086 2 : pszBandIndexingVarItem);
12087 2 : if (pszVal)
12088 1 : nMaxLen = std::max(nMaxLen, strlen(pszVal));
12089 : }
12090 : }
12091 : const auto oIndexingVarType =
12092 3 : EQUAL(pszBandIndexingVarType, "String")
12093 : ? GDALExtendedDataType::CreateString(nMaxLen)
12094 2 : : EQUAL(pszBandIndexingVarType, "Integer")
12095 : ? GDALExtendedDataType::Create(GDT_Int32)
12096 6 : : GDALExtendedDataType::Create(GDT_Float64);
12097 3 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12098 12 : {poBandDim}, oIndexingVarType);
12099 3 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12100 9 : for (int i = 0; i < nBandCount; ++i)
12101 : {
12102 6 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12103 6 : const size_t anCount[] = {1};
12104 6 : const GInt64 arrayStep[] = {1};
12105 6 : const GPtrDiff_t anBufferStride[] = {1};
12106 : const char *pszVal =
12107 6 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
12108 6 : pszBandIndexingVarItem);
12109 6 : if (oIndexingVarType.GetClass() == GEDTC_STRING)
12110 : {
12111 2 : const char *const apszBandVal[] = {pszVal ? pszVal : ""};
12112 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12113 : anBufferStride, oIndexingVarType,
12114 : apszBandVal);
12115 : }
12116 4 : else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12117 : {
12118 2 : const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12119 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12120 : anBufferStride, oIndexingVarType, anVal);
12121 : }
12122 : else
12123 : {
12124 2 : const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12125 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12126 : anBufferStride, oIndexingVarType, adfVal);
12127 : }
12128 : }
12129 3 : m_varBand = std::move(poBandVar);
12130 3 : poBandDim->SetIndexingVariable(m_varBand);
12131 : }
12132 :
12133 17 : GDALGeoTransform gt;
12134 17 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12135 : {
12136 24 : m_varX = GDALMDArrayRegularlySpaced::Create(
12137 16 : "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12138 8 : poXDim->SetIndexingVariable(m_varX);
12139 :
12140 24 : m_varY = GDALMDArrayRegularlySpaced::Create(
12141 16 : "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12142 8 : poYDim->SetIndexingVariable(m_varY);
12143 : }
12144 17 : if (bBandYX)
12145 : {
12146 96 : m_dims = {std::move(poBandDim), std::move(poYDim),
12147 80 : std::move(poXDim)};
12148 : }
12149 : else
12150 : {
12151 1 : m_iYDim = 0;
12152 1 : m_iXDim = 1;
12153 1 : m_iBandDim = 2;
12154 6 : m_dims = {std::move(poYDim), std::move(poXDim),
12155 5 : std::move(poBandDim)};
12156 : }
12157 17 : }
12158 :
12159 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12160 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12161 : const GDALExtendedDataType &bufferDataType,
12162 : void *pDstBuffer) const override;
12163 :
12164 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12165 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12166 : const GDALExtendedDataType &bufferDataType,
12167 : const void *pSrcBuffer) override
12168 : {
12169 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12170 : bufferStride, bufferDataType,
12171 1 : const_cast<void *>(pSrcBuffer));
12172 : }
12173 :
12174 : public:
12175 34 : ~GDALMDArrayFromDataset() override
12176 17 : {
12177 17 : m_poDS->ReleaseRef();
12178 34 : }
12179 :
12180 17 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12181 : CSLConstList papszOptions)
12182 : {
12183 : auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12184 34 : new GDALMDArrayFromDataset(poDS, papszOptions)));
12185 17 : array->SetSelf(array);
12186 34 : return array;
12187 : }
12188 :
12189 2 : bool IsWritable() const override
12190 : {
12191 2 : return m_poDS->GetAccess() == GA_Update;
12192 : }
12193 :
12194 14 : const std::string &GetFilename() const override
12195 : {
12196 14 : return m_osFilename;
12197 : }
12198 :
12199 : const std::vector<std::shared_ptr<GDALDimension>> &
12200 100 : GetDimensions() const override
12201 : {
12202 100 : return m_dims;
12203 : }
12204 :
12205 36 : const GDALExtendedDataType &GetDataType() const override
12206 : {
12207 36 : return m_dt;
12208 : }
12209 :
12210 5 : const std::string &GetUnit() const override
12211 : {
12212 5 : return m_osUnit;
12213 : }
12214 :
12215 5 : const void *GetRawNoDataValue() const override
12216 : {
12217 5 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12218 : }
12219 :
12220 5 : double GetOffset(bool *pbHasOffset,
12221 : GDALDataType *peStorageType) const override
12222 : {
12223 5 : double dfRes = 0;
12224 5 : int bHasOffset = false;
12225 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12226 5 : if (poFirstBand) // to avoid -Wnull-dereference
12227 : {
12228 5 : dfRes = poFirstBand->GetOffset(&bHasOffset);
12229 7 : for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12230 : {
12231 : const double dfOtherRes =
12232 2 : m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12233 2 : bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12234 : }
12235 : }
12236 5 : if (pbHasOffset)
12237 5 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12238 5 : if (peStorageType)
12239 3 : *peStorageType = GDT_Unknown;
12240 5 : return dfRes;
12241 : }
12242 :
12243 5 : double GetScale(bool *pbHasScale,
12244 : GDALDataType *peStorageType) const override
12245 : {
12246 5 : double dfRes = 0;
12247 5 : int bHasScale = false;
12248 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12249 5 : if (poFirstBand) // to avoid -Wnull-dereference
12250 : {
12251 5 : dfRes = poFirstBand->GetScale(&bHasScale);
12252 7 : for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12253 : {
12254 : const double dfOtherRes =
12255 2 : m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12256 2 : bHasScale = bHasScale && (dfOtherRes == dfRes);
12257 : }
12258 : }
12259 5 : if (pbHasScale)
12260 5 : *pbHasScale = CPL_TO_BOOL(bHasScale);
12261 5 : if (peStorageType)
12262 3 : *peStorageType = GDT_Unknown;
12263 5 : return dfRes;
12264 : }
12265 :
12266 9 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12267 : {
12268 9 : auto poSrcSRS = m_poDS->GetSpatialRef();
12269 9 : if (!poSrcSRS)
12270 1 : return nullptr;
12271 16 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12272 :
12273 16 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12274 24 : for (auto &m : axisMapping)
12275 : {
12276 16 : if (m == 1)
12277 8 : m = m_iXDim + 1;
12278 8 : else if (m == 2)
12279 8 : m = m_iYDim + 1;
12280 : else
12281 0 : m = 0;
12282 : }
12283 8 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12284 8 : return poSRS;
12285 : }
12286 :
12287 7 : std::vector<GUInt64> GetBlockSize() const override
12288 : {
12289 7 : int nBlockXSize = 0;
12290 7 : int nBlockYSize = 0;
12291 7 : m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12292 7 : if (m_iBandDim == 0)
12293 : {
12294 6 : return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12295 6 : static_cast<GUInt64>(nBlockXSize)};
12296 : }
12297 : else
12298 : {
12299 1 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12300 1 : static_cast<GUInt64>(nBlockXSize), 1};
12301 : }
12302 : }
12303 :
12304 : std::vector<std::shared_ptr<GDALAttribute>>
12305 7 : GetAttributes(CSLConstList) const override
12306 : {
12307 7 : std::vector<std::shared_ptr<GDALAttribute>> res;
12308 7 : auto papszMD = m_poDS->GetMetadata();
12309 14 : for (auto iter = papszMD; iter && iter[0]; ++iter)
12310 : {
12311 7 : char *pszKey = nullptr;
12312 7 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12313 7 : if (pszKey && pszValue)
12314 : {
12315 : res.emplace_back(
12316 7 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12317 : }
12318 7 : CPLFree(pszKey);
12319 : }
12320 7 : return res;
12321 : }
12322 :
12323 6 : int GetOverviewCount() const override
12324 : {
12325 6 : int nOvrCount = 0;
12326 6 : GDALDataset *poOvrDS = nullptr;
12327 6 : bool bOK = true;
12328 12 : for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12329 : {
12330 6 : auto poBand = m_poDS->GetRasterBand(i);
12331 6 : const int nThisOvrCount = poBand->GetOverviewCount();
12332 6 : bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12333 6 : if (bOK)
12334 : {
12335 6 : nOvrCount = nThisOvrCount;
12336 6 : auto poFirstOvrBand = poBand->GetOverview(0);
12337 6 : bOK = poFirstOvrBand != nullptr;
12338 6 : if (bOK)
12339 : {
12340 6 : auto poThisOvrDS = poFirstOvrBand->GetDataset();
12341 12 : bOK = poThisOvrDS != nullptr &&
12342 6 : poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12343 0 : (i == 1 || poThisOvrDS == poOvrDS);
12344 6 : if (bOK)
12345 6 : poOvrDS = poThisOvrDS;
12346 : }
12347 : }
12348 : }
12349 6 : return bOK ? nOvrCount : 0;
12350 : }
12351 :
12352 5 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12353 : {
12354 5 : const int nOverviews = GetOverviewCount();
12355 5 : if (idx < 0 || idx >= nOverviews)
12356 2 : return nullptr;
12357 3 : m_apoOverviews.resize(nOverviews);
12358 3 : if (!m_apoOverviews[idx])
12359 : {
12360 1 : if (auto poBand = m_poDS->GetRasterBand(1))
12361 : {
12362 1 : if (auto poOvrBand = poBand->GetOverview(idx))
12363 : {
12364 1 : if (auto poOvrDS = poOvrBand->GetDataset())
12365 : {
12366 1 : m_apoOverviews[idx] =
12367 2 : Create(poOvrDS, m_aosOptions.List());
12368 : }
12369 : }
12370 : }
12371 : }
12372 3 : return m_apoOverviews[idx];
12373 : }
12374 : };
12375 :
12376 8 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12377 : const size_t *count, const GInt64 *arrayStep,
12378 : const GPtrDiff_t *bufferStride,
12379 : const GDALExtendedDataType &bufferDataType,
12380 : void *pDstBuffer) const
12381 : {
12382 8 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12383 8 : bufferDataType, pDstBuffer);
12384 : }
12385 :
12386 : /************************************************************************/
12387 : /* ReadWrite() */
12388 : /************************************************************************/
12389 :
12390 9 : bool GDALMDArrayFromDataset::ReadWrite(
12391 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12392 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12393 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12394 : {
12395 9 : const auto eDT(bufferDataType.GetNumericDataType());
12396 9 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12397 9 : const int nX =
12398 9 : arrayStep[m_iXDim] > 0
12399 9 : ? static_cast<int>(arrayStartIdx[m_iXDim])
12400 0 : : static_cast<int>(arrayStartIdx[m_iXDim] -
12401 0 : (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12402 9 : const int nY =
12403 9 : arrayStep[m_iYDim] > 0
12404 9 : ? static_cast<int>(arrayStartIdx[m_iYDim])
12405 1 : : static_cast<int>(arrayStartIdx[m_iYDim] -
12406 1 : (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12407 : const int nSizeX =
12408 9 : static_cast<int>(count[m_iXDim] * std::abs(arrayStep[m_iXDim]));
12409 : const int nSizeY =
12410 9 : static_cast<int>(count[m_iYDim] * std::abs(arrayStep[m_iYDim]));
12411 9 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12412 9 : int nStrideXSign = 1;
12413 9 : if (arrayStep[m_iXDim] < 0)
12414 : {
12415 0 : pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12416 0 : nStrideXSign = -1;
12417 : }
12418 9 : int nStrideYSign = 1;
12419 9 : if (arrayStep[m_iYDim] < 0)
12420 : {
12421 1 : pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12422 1 : nStrideYSign = -1;
12423 : }
12424 9 : const GSpacing nPixelSpace =
12425 9 : static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12426 9 : const GSpacing nLineSpace =
12427 9 : static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12428 9 : const GSpacing nBandSpace =
12429 9 : static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12430 9 : std::vector<int> anBandList;
12431 26 : for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12432 17 : anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12433 17 : i * static_cast<int>(arrayStep[m_iBandDim]));
12434 :
12435 27 : return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12436 9 : static_cast<int>(count[m_iXDim]),
12437 9 : static_cast<int>(count[m_iYDim]), eDT,
12438 9 : static_cast<int>(count[m_iBandDim]),
12439 9 : anBandList.data(), nPixelSpace, nLineSpace,
12440 18 : nBandSpace, nullptr) == CE_None;
12441 : }
12442 :
12443 : /************************************************************************/
12444 : /* AsMDArray() */
12445 : /************************************************************************/
12446 :
12447 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12448 : *
12449 : * If this dataset is not already marked as shared, it will be, so that the
12450 : * returned array holds a reference to it.
12451 : *
12452 : * If the dataset has a geotransform attached, the X and Y dimensions of the
12453 : * returned array will have an associated indexing variable.
12454 : *
12455 : * The currently supported list of options is:
12456 : * <ul>
12457 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12458 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
12459 : * and the last (fastest changing direction) is X
12460 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
12461 : * and the last (fastest changing direction) is Band.
12462 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12463 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12464 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12465 : * "Y,X,Band" is use.
12466 : * </li>
12467 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
12468 : * item from which to build the band indexing variable.
12469 : * <ul>
12470 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12471 : * <li>"{None}" means that no band indexing variable must be created.</li>
12472 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
12473 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12474 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
12475 : * </ul>
12476 : * </li>
12477 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12478 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12479 : * Defaults to String.
12480 : * </li>
12481 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
12482 : * Defaults to "Band".
12483 : * </li>
12484 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
12485 : * </li>
12486 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
12487 : * </li>
12488 : * </ul>
12489 : *
12490 : * This is the same as the C function GDALDatasetAsMDArray().
12491 : *
12492 : * The "reverse" method is GDALMDArray::AsClassicDataset().
12493 : *
12494 : * @param papszOptions Null-terminated list of strings, or nullptr.
12495 : * @return a new array, or nullptr.
12496 : *
12497 : * @since GDAL 3.12
12498 : */
12499 19 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12500 : {
12501 19 : if (!GetShared())
12502 : {
12503 18 : MarkAsShared();
12504 : }
12505 19 : if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12506 : {
12507 1 : ReportError(
12508 : CE_Failure, CPLE_AppDefined,
12509 : "Degenerated array (band, Y and/or X dimension of size zero)");
12510 1 : return nullptr;
12511 : }
12512 18 : const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12513 31 : for (int i = 1; i < nBands; ++i)
12514 : {
12515 14 : if (eDT != papoBands[i]->GetRasterDataType())
12516 : {
12517 1 : ReportError(CE_Failure, CPLE_AppDefined,
12518 : "Non-uniform data type amongst bands");
12519 1 : return nullptr;
12520 : }
12521 : }
12522 : const char *pszDimOrder =
12523 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12524 17 : if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12525 2 : !EQUAL(pszDimOrder, "Y,X,Band"))
12526 : {
12527 1 : ReportError(CE_Failure, CPLE_IllegalArg,
12528 : "Illegal value for DIM_ORDER option");
12529 1 : return nullptr;
12530 : }
12531 16 : return GDALMDArrayFromDataset::Create(this, papszOptions);
12532 : }
12533 :
12534 : /************************************************************************/
12535 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12536 : /************************************************************************/
12537 :
12538 : /**
12539 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12540 :
12541 : The covariance indicates the level to which two bands vary together.
12542 :
12543 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12544 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12545 :
12546 : \f[
12547 : \mathrm{cov}[i,j] =
12548 : \frac{
12549 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12550 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12551 : }{
12552 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12553 : }
12554 : \f]
12555 :
12556 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12557 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12558 : is symmetric.
12559 :
12560 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12561 : if the pixels in bands are considered to be a sample of the whole population.
12562 : This is consistent with the default of
12563 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12564 : matrix is consistent with what can be obtained with
12565 :
12566 : \verbatim embed:rst
12567 : .. code-block:: python
12568 :
12569 : numpy.cov(
12570 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12571 : )
12572 : \endverbatim
12573 :
12574 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12575 : to be the whole population.
12576 :
12577 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12578 : this method uses them.
12579 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12580 : Otherwise, if bForce is false, an empty vector is returned
12581 :
12582 : @param nBandCount Zero for all bands, or number of values in panBandList.
12583 : Defaults to 0.
12584 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12585 : nBandCount values such as panBandList[i] is the index
12586 : between 1 and GetRasterCount() of a band that must be used
12587 : in the covariance computation. Defaults to nullptr.
12588 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12589 : ComputeInterBandCovarianceMatrix().
12590 : Defaults to false.
12591 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12592 : when the STATISTICS_COVARIANCES metadata items are missing.
12593 : Defaults to false.
12594 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12595 : write STATISTICS_COVARIANCES band metadata items.
12596 : Defaults to true.
12597 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12598 : averaging phase of the covariance computation.
12599 : Defaults to 1.
12600 : @param pfnProgress a function to call to report progress, or NULL.
12601 : @param pProgressData application data to pass to the progress function.
12602 :
12603 : @return a vector of nBandCount * nBandCount values if successful,
12604 : in row-major order, or an empty vector in case of failure
12605 :
12606 : @since 3.13
12607 :
12608 : @see ComputeInterBandCovarianceMatrix()
12609 : */
12610 :
12611 0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12612 : int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12613 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12614 : GDALProgressFunc pfnProgress, void *pProgressData)
12615 : {
12616 0 : std::vector<double> res;
12617 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12618 0 : if (nBandCountToUse == 0)
12619 0 : return res;
12620 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12621 : {
12622 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12623 : if (static_cast<uint32_t>(nBandCountToUse) >
12624 : std::numeric_limits<uint16_t>::max())
12625 : {
12626 : CPLError(CE_Failure, CPLE_OutOfMemory,
12627 : "Not enough memory to store result");
12628 : return res;
12629 : }
12630 : }
12631 : try
12632 : {
12633 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12634 : }
12635 0 : catch (const std::exception &)
12636 : {
12637 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12638 : "Not enough memory to store result");
12639 0 : return res;
12640 : }
12641 :
12642 0 : if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12643 : panBandList, bApproxOK, bForce,
12644 : bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12645 0 : pfnProgress, pProgressData) != CE_None)
12646 : {
12647 0 : res.clear();
12648 : }
12649 0 : return res;
12650 : }
12651 :
12652 : /************************************************************************/
12653 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12654 : /************************************************************************/
12655 :
12656 : /**
12657 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12658 :
12659 : The covariance indicates the level to which two bands vary together.
12660 :
12661 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12662 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12663 :
12664 : \f[
12665 : \mathrm{cov}[i,j] =
12666 : \frac{
12667 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12668 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12669 : }{
12670 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12671 : }
12672 : \f]
12673 :
12674 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12675 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12676 : is symmetric.
12677 :
12678 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12679 : if the pixels in bands are considered to be a sample of the whole population.
12680 : This is consistent with the default of
12681 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12682 : matrix is consistent with what can be obtained with
12683 :
12684 : \verbatim embed:rst
12685 : .. code-block:: python
12686 :
12687 : numpy.cov(
12688 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12689 : )
12690 : \endverbatim
12691 :
12692 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12693 : to be the whole population.
12694 :
12695 : The caller must provide an already allocated array in padfCovMatrix of size
12696 : at least nBandCount * nBandCount.
12697 :
12698 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12699 : this method uses them.
12700 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12701 : Otherwise, if bForce is false, an empty vector is returned
12702 :
12703 : This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12704 :
12705 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12706 : nBandCount * nBandCount.
12707 : @param nSize Number of elements in output array.
12708 : @param nBandCount Zero for all bands, or number of values in panBandList.
12709 : Defaults to 0.
12710 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12711 : nBandCount values such as panBandList[i] is the index
12712 : between 1 and GetRasterCount() of a band that must be used
12713 : in the covariance computation. Defaults to nullptr.
12714 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12715 : ComputeInterBandCovarianceMatrix().
12716 : Defaults to false.
12717 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12718 : when the STATISTICS_COVARIANCES metadata items are missing.
12719 : Defaults to false.
12720 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12721 : write STATISTICS_COVARIANCES band metadata items.
12722 : Defaults to true.
12723 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12724 : averaging phase of the covariance computation.
12725 : Defaults to 1.
12726 : @param pfnProgress a function to call to report progress, or NULL.
12727 : @param pProgressData application data to pass to the progress function.
12728 :
12729 : @return CE_None if successful, CE_Warning if values are not available in
12730 : metadata and bForce is false, or CE_Failure in case of failure
12731 :
12732 : @since 3.13
12733 :
12734 : @see ComputeInterBandCovarianceMatrix()
12735 : */
12736 :
12737 11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12738 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12739 : bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12740 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12741 : void *pProgressData)
12742 : {
12743 22 : std::vector<int> anBandListTmp; // keep in this scope
12744 11 : if (nBandCount == 0)
12745 : {
12746 0 : if (nBands == 0)
12747 0 : return CE_None;
12748 0 : for (int i = 0; i < nBands; ++i)
12749 0 : anBandListTmp.push_back(i + 1);
12750 0 : nBandCount = nBands;
12751 0 : panBandList = anBandListTmp.data();
12752 : }
12753 : else
12754 : {
12755 11 : if (nBandCount > nBands)
12756 : {
12757 1 : CPLError(CE_Failure, CPLE_AppDefined,
12758 : "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12759 1 : return CE_Failure;
12760 : }
12761 29 : for (int i = 0; i < nBandCount; ++i)
12762 : {
12763 21 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
12764 : {
12765 2 : CPLError(CE_Failure, CPLE_AppDefined,
12766 : "GetInterBandCovarianceMatrix(): invalid value "
12767 : "panBandList[%d] = %d",
12768 2 : i, panBandList[i]);
12769 2 : return CE_Failure;
12770 : }
12771 : }
12772 : }
12773 :
12774 8 : if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12775 : {
12776 0 : CPLError(
12777 : CE_Failure, CPLE_AppDefined,
12778 : "GetInterBandCovarianceMatrix(): too small result matrix provided");
12779 0 : return CE_Failure;
12780 : }
12781 8 : bool bGotFromMD = true;
12782 8 : size_t resIdx = 0;
12783 20 : for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12784 : {
12785 24 : const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12786 12 : "STATISTICS_COVARIANCES");
12787 12 : bGotFromMD = pszCov != nullptr;
12788 12 : if (bGotFromMD)
12789 : {
12790 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12791 6 : bGotFromMD = aosTokens.size() == nBands;
12792 6 : if (bGotFromMD)
12793 : {
12794 24 : for (int j = 0; j < nBandCount; ++j)
12795 18 : padfCovMatrix[resIdx++] =
12796 18 : CPLAtof(aosTokens[panBandList[j] - 1]);
12797 : }
12798 : }
12799 : }
12800 8 : if (bGotFromMD)
12801 2 : return CE_None;
12802 :
12803 6 : if (!bForce)
12804 1 : return CE_Warning;
12805 5 : return ComputeInterBandCovarianceMatrix(
12806 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12807 5 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12808 : }
12809 :
12810 : /************************************************************************/
12811 : /* GDALDatasetGetInterBandCovarianceMatrix() */
12812 : /************************************************************************/
12813 :
12814 : /**
12815 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12816 :
12817 : The covariance indicates the level to which two bands vary together.
12818 :
12819 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12820 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12821 :
12822 : \f[
12823 : \mathrm{cov}[i,j] =
12824 : \frac{
12825 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12826 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12827 : }{
12828 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12829 : }
12830 : \f]
12831 :
12832 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12833 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12834 : is symmetric.
12835 :
12836 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12837 : if the pixels in bands are considered to be a sample of the whole population.
12838 : This is consistent with the default of
12839 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12840 : matrix is consistent with what can be obtained with
12841 :
12842 : \verbatim embed:rst
12843 : .. code-block:: python
12844 :
12845 : numpy.cov(
12846 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12847 : )
12848 : \endverbatim
12849 :
12850 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12851 : to be the whole population.
12852 :
12853 : The caller must provide an already allocated array in padfCovMatrix of size
12854 : at least nBandCount * nBandCount.
12855 :
12856 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12857 : this method uses them.
12858 : Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12859 : Otherwise, if bForce is false, an empty vector is returned
12860 :
12861 : This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12862 :
12863 : @param hDS Dataset handle.
12864 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12865 : nBandCount * nBandCount.
12866 : @param nSize Number of elements in output array.
12867 : @param nBandCount Zero for all bands, or number of values in panBandList.
12868 : Defaults to 0.
12869 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12870 : nBandCount values such as panBandList[i] is the index
12871 : between 1 and GetRasterCount() of a band that must be used
12872 : in the covariance computation. Defaults to nullptr.
12873 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12874 : GDALDatasetComputeInterBandCovarianceMatrix().
12875 : Defaults to false.
12876 : @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12877 : when the STATISTICS_COVARIANCES metadata items are missing.
12878 : Defaults to false.
12879 : @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12880 : write STATISTICS_COVARIANCES band metadata items.
12881 : Defaults to true.
12882 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12883 : averaging phase of the covariance computation.
12884 : Defaults to 1.
12885 : @param pfnProgress a function to call to report progress, or NULL.
12886 : @param pProgressData application data to pass to the progress function.
12887 :
12888 : @return CE_None if successful, CE_Warning if values are not available in
12889 : metadata and bForce is false, or CE_Failure in case of failure
12890 :
12891 : @since 3.13
12892 :
12893 : @see GDALDatasetComputeInterBandCovarianceMatrix()
12894 : */
12895 11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12896 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12897 : const int *panBandList, bool bApproxOK, bool bForce,
12898 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12899 : GDALProgressFunc pfnProgress, void *pProgressData)
12900 : {
12901 11 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12902 11 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12903 11 : return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12904 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12905 11 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12906 : }
12907 :
12908 : /************************************************************************/
12909 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
12910 : /************************************************************************/
12911 :
12912 : /**
12913 : \brief Compute the covariance matrix between bands of this dataset.
12914 :
12915 : The covariance indicates the level to which two bands vary together.
12916 :
12917 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12918 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12919 :
12920 : \f[
12921 : \mathrm{cov}[i,j] =
12922 : \frac{
12923 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12924 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12925 : }{
12926 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12927 : }
12928 : \f]
12929 :
12930 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12931 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12932 : is symmetric.
12933 :
12934 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12935 : if the pixels in bands are considered to be a sample of the whole population.
12936 : This is consistent with the default of
12937 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12938 : matrix is consistent with what can be obtained with
12939 :
12940 : \verbatim embed:rst
12941 : .. code-block:: python
12942 :
12943 : numpy.cov(
12944 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12945 : )
12946 : \endverbatim
12947 :
12948 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12949 : to be the whole population.
12950 :
12951 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12952 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
12953 : to use them.
12954 :
12955 : @param nBandCount Zero for all bands, or number of values in panBandList.
12956 : Defaults to 0.
12957 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12958 : nBandCount values such as panBandList[i] is the index
12959 : between 1 and GetRasterCount() of a band that must be used
12960 : in the covariance computation. Defaults to nullptr.
12961 : @param bApproxOK Whether it is acceptable to use a subsample of values.
12962 : Defaults to false.
12963 : @param bWriteIntoMetadata Whether this method must write
12964 : STATISTICS_COVARIANCES band metadata items.
12965 : Defaults to true.
12966 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12967 : averaging phase of the covariance computation.
12968 : Defaults to 1.
12969 : @param pfnProgress a function to call to report progress, or NULL.
12970 : @param pProgressData application data to pass to the progress function.
12971 :
12972 : @return a vector of nBandCount * nBandCount values if successful,
12973 : in row-major order, or an empty vector in case of failure
12974 :
12975 : @since 3.13
12976 :
12977 : @see GetInterBandCovarianceMatrix()
12978 : */
12979 0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12980 : int nBandCount, const int *panBandList, bool bApproxOK,
12981 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12982 : GDALProgressFunc pfnProgress, void *pProgressData)
12983 : {
12984 0 : std::vector<double> res;
12985 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12986 0 : if (nBandCountToUse == 0)
12987 0 : return res;
12988 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12989 : {
12990 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12991 : if (static_cast<uint32_t>(nBandCountToUse) >
12992 : std::numeric_limits<uint16_t>::max())
12993 : {
12994 : CPLError(CE_Failure, CPLE_OutOfMemory,
12995 : "Not enough memory to store result");
12996 : return res;
12997 : }
12998 : }
12999 : try
13000 : {
13001 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
13002 : }
13003 0 : catch (const std::exception &)
13004 : {
13005 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
13006 : "Not enough memory to store result");
13007 0 : return res;
13008 : }
13009 :
13010 0 : if (ComputeInterBandCovarianceMatrix(
13011 : res.data(), res.size(), nBandCount, panBandList, bApproxOK,
13012 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
13013 0 : pProgressData) != CE_None)
13014 0 : res.clear();
13015 0 : return res;
13016 : }
13017 :
13018 : /************************************************************************/
13019 : /* ComputeInterBandCovarianceMatrixInternal() */
13020 : /************************************************************************/
13021 :
13022 : template <class T>
13023 : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
13024 : // causes that to happen
13025 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
13026 15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
13027 : double *padfCovMatrix, int nBandCount,
13028 : const int *panBandList,
13029 : GDALRasterBand *const *papoBands,
13030 : int nDeltaDegreeOfFreedom,
13031 : GDALProgressFunc pfnProgress,
13032 : void *pProgressData)
13033 : {
13034 : // We use the padfCovMatrix to accumulate co-moments
13035 : // Dimension = nBandCount * nBandCount
13036 15 : double *const padfComomentMatrix = padfCovMatrix;
13037 :
13038 : // Matrix of nBandCount * nBandCount storing co-moments, in optimized
13039 : // case when the block has no nodata value
13040 : // Only used if T != double
13041 30 : [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
13042 :
13043 : // Count number of valid values in padfComomentMatrix for each (i,j) tuple
13044 : // Updated while iterating over blocks
13045 : // Dimension = nBandCount * nBandCount
13046 30 : std::vector<uint64_t> anCount;
13047 :
13048 : // Mean of bands, for each (i,j) tuple.
13049 : // Updated while iterating over blocks.
13050 : // This is a matrix rather than a vector due to the fact when need to update
13051 : // it in sync with padfComomentMatrix
13052 : // Dimension = nBandCount * nBandCount
13053 30 : std::vector<T> adfMean;
13054 :
13055 : // Number of valid values when computing adfMean, for each (i,j) tuple.
13056 : // Updated while iterating over blocks.
13057 : // This is a matrix rather than a vector due to the fact when need to update
13058 : // it in sync with padfComomentMatrix
13059 : // Dimension = nBandCount * nBandCount
13060 30 : std::vector<uint64_t> anCountMean;
13061 :
13062 : // Mean of values for each band i. Refreshed for each block.
13063 : // Dimension = nBandCount
13064 30 : std::vector<T> adfCurBlockMean;
13065 :
13066 : // Number of values participating to the mean for each band i.
13067 : // Refreshed for each block. Dimension = nBandCount
13068 30 : std::vector<size_t> anCurBlockCount;
13069 :
13070 : // Pixel values for all selected values for the current block
13071 : // Dimension = nBlockXSize * nBlockYSize * nBandCount
13072 30 : std::vector<T> adfCurBlockPixelsAllBands;
13073 :
13074 : // Vector of nodata values for all bands. Dimension = nBandCount
13075 30 : std::vector<T> adfNoData;
13076 :
13077 : // Vector of mask bands for all bands. Dimension = nBandCount
13078 30 : std::vector<GDALRasterBand *> apoMaskBands;
13079 :
13080 : // Vector of vector of mask values. Dimension = nBandCount
13081 30 : std::vector<std::vector<GByte>> aabyCurBlockMask;
13082 :
13083 : // Vector of pointer to vector of mask values. Dimension = nBandCount
13084 30 : std::vector<std::vector<GByte> *> pabyCurBlockMask;
13085 :
13086 15 : int nBlockXSize = 0;
13087 15 : int nBlockYSize = 0;
13088 15 : papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
13089 :
13090 30 : if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
13091 15 : std::numeric_limits<size_t>::max() / nBandCount)
13092 : {
13093 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13094 : "Not enough memory for intermediate computations");
13095 0 : return CE_Failure;
13096 : }
13097 15 : const size_t nPixelsInBlock =
13098 15 : static_cast<size_t>(nBlockXSize) * nBlockYSize;
13099 :
13100 : // Allocate temporary matrices and vectors
13101 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13102 :
13103 : using MySignedSize_t = std::make_signed_t<size_t>;
13104 15 : const auto kMax =
13105 15 : static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
13106 30 : std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
13107 : try
13108 : {
13109 15 : anCount.resize(nMatrixSize);
13110 15 : adfMean.resize(nMatrixSize);
13111 15 : anCountMean.resize(nMatrixSize);
13112 :
13113 : if constexpr (!std::is_same_v<T, double>)
13114 : {
13115 : aCurBlockComomentMatrix.resize(nMatrixSize);
13116 : }
13117 :
13118 15 : anMapLinearIdxToIJ.resize(kMax);
13119 :
13120 15 : adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13121 :
13122 15 : adfCurBlockMean.resize(nBandCount);
13123 15 : anCurBlockCount.resize(nBandCount);
13124 15 : adfNoData.resize(nBandCount);
13125 15 : apoMaskBands.resize(nBandCount);
13126 15 : aabyCurBlockMask.resize(nBandCount);
13127 15 : pabyCurBlockMask.resize(nBandCount);
13128 : }
13129 0 : catch (const std::exception &)
13130 : {
13131 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13132 : "Not enough memory for intermediate computations");
13133 0 : return CE_Failure;
13134 : }
13135 :
13136 15 : constexpr T ZERO{0};
13137 15 : std::fill(padfComomentMatrix,
13138 15 : padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13139 15 : 0);
13140 :
13141 : {
13142 15 : MySignedSize_t nLinearIdx = 0;
13143 1045 : for (int i = 0; i < nBandCount; ++i)
13144 : {
13145 501581 : for (int j = i; j < nBandCount; ++j)
13146 : {
13147 500551 : anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13148 500551 : ++nLinearIdx;
13149 : }
13150 : }
13151 : }
13152 :
13153 : // Fetch nodata values and mask bands
13154 15 : bool bAllBandsSameMask = false;
13155 15 : bool bIsAllInteger = false;
13156 15 : bool bNoneHasMaskOrNodata = false;
13157 1045 : for (int i = 0; i < nBandCount; ++i)
13158 : {
13159 1030 : const auto poBand = papoBands[panBandList[i] - 1];
13160 2057 : bIsAllInteger = (i == 0 || bIsAllInteger) &&
13161 1027 : GDALDataTypeIsInteger(poBand->GetRasterDataType());
13162 1030 : int bHasNoData = FALSE;
13163 1030 : double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13164 1030 : if (!bHasNoData)
13165 : {
13166 1028 : dfNoData = std::numeric_limits<double>::quiet_NaN();
13167 :
13168 1032 : if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13169 4 : poBand->GetColorInterpretation() != GCI_AlphaBand)
13170 : {
13171 4 : apoMaskBands[i] = poBand->GetMaskBand();
13172 : try
13173 : {
13174 4 : aabyCurBlockMask[i].resize(nPixelsInBlock);
13175 : }
13176 0 : catch (const std::exception &)
13177 : {
13178 0 : poDS->ReportError(
13179 : CE_Failure, CPLE_OutOfMemory,
13180 : "Not enough memory for intermediate computations");
13181 0 : return CE_Failure;
13182 : }
13183 : #ifndef __COVERITY__
13184 : // coverity[escape]
13185 4 : pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13186 : #endif
13187 : }
13188 : }
13189 1030 : adfNoData[i] = static_cast<T>(dfNoData);
13190 1030 : if (i == 0)
13191 15 : bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13192 1015 : else if (bAllBandsSameMask)
13193 2 : bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13194 :
13195 3072 : bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13196 3072 : std::isnan(dfNoData) &&
13197 1026 : apoMaskBands[i] == nullptr;
13198 : }
13199 15 : if (bAllBandsSameMask)
13200 : {
13201 2 : for (int i = 1; i < nBandCount; ++i)
13202 : {
13203 1 : apoMaskBands[i] = nullptr;
13204 1 : aabyCurBlockMask[i].clear();
13205 1 : pabyCurBlockMask[i] = pabyCurBlockMask[0];
13206 : }
13207 : }
13208 :
13209 15 : const auto nIterCount =
13210 : static_cast<uint64_t>(
13211 15 : cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13212 15 : cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13213 15 : uint64_t nCurIter = 0;
13214 :
13215 15 : int nNumThreads = 1;
13216 : #ifdef HAVE_OPENMP
13217 15 : if (nBandCount >= 100)
13218 : {
13219 1 : const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13220 : nNumThreads =
13221 1 : GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13222 : }
13223 : #endif
13224 :
13225 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13226 30 : const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13227 30 : __builtin_cpu_supports("avx2") &&
13228 : __builtin_cpu_supports("fma");
13229 : #endif
13230 :
13231 : // Iterate over all blocks
13232 77 : for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13233 : {
13234 32 : const auto nThisBlockPixelCount =
13235 32 : static_cast<size_t>(window.nXSize) * window.nYSize;
13236 :
13237 : // Extract pixel values and masks
13238 96 : CPLErr eErr = poDS->RasterIO(
13239 32 : GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13240 32 : adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13241 : gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13242 : nullptr);
13243 32 : if (eErr == CE_None && bAllBandsSameMask)
13244 : {
13245 2 : eErr = apoMaskBands[0]->RasterIO(
13246 1 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13247 1 : window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13248 1 : window.nYSize, GDT_Byte, 0, 0, nullptr);
13249 : }
13250 : else
13251 : {
13252 1108 : for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13253 : {
13254 1077 : if (apoMaskBands[i])
13255 : {
13256 4 : eErr = apoMaskBands[i]->RasterIO(
13257 2 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13258 2 : window.nYSize, aabyCurBlockMask[i].data(),
13259 2 : window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13260 : }
13261 : }
13262 : }
13263 32 : if (eErr != CE_None)
13264 1 : return eErr;
13265 :
13266 : // Compute the mean of all bands for this block
13267 32 : bool bAllBandsAreAllNodata = false;
13268 32 : bool bNoBandHasNodata = false;
13269 1111 : for (int i = 0; i < nBandCount; ++i)
13270 : {
13271 1079 : T dfSum = 0;
13272 1079 : size_t nCount = 0;
13273 1079 : const T dfNoDataI = adfNoData[i];
13274 1079 : const T *padfI =
13275 1079 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13276 : #ifdef HAVE_OPENMP_SIMD
13277 1079 : #pragma omp simd reduction(+ : dfSum)
13278 : #endif
13279 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13280 : {
13281 822482 : const T dfI = padfI[iPixel];
13282 822482 : const bool bIsValid =
13283 1644950 : !std::isnan(dfI) && dfI != dfNoDataI &&
13284 822466 : (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13285 822482 : nCount += bIsValid;
13286 822482 : dfSum += bIsValid ? dfI : ZERO;
13287 : }
13288 1079 : adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13289 1079 : anCurBlockCount[i] = nCount;
13290 1079 : bAllBandsAreAllNodata =
13291 1079 : (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13292 1079 : bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13293 : (nCount == nThisBlockPixelCount);
13294 : }
13295 :
13296 : // Modify the pixel values to shift them by minus the mean
13297 32 : if (!bAllBandsAreAllNodata)
13298 : {
13299 1103 : for (int i = 0; i < nBandCount; ++i)
13300 : {
13301 1074 : T *padfI =
13302 1074 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13303 1074 : const T dfMeanI = adfCurBlockMean[i];
13304 823546 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13305 : {
13306 822472 : padfI[iPixel] -= dfMeanI;
13307 : }
13308 : }
13309 : }
13310 :
13311 : // Update padfComomentMatrix, anCount, adfMean, anCountMean
13312 : // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13313 32 : const auto UpdateGlobalValues =
13314 13507600 : [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13315 : &anCurBlockCount, padfComomentMatrix,
13316 : nBandCount](int i, int j, size_t nCount, T dfComoment)
13317 : {
13318 500647 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13319 500647 : const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13320 :
13321 : // Update the total comoment using last formula of paragraph
13322 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13323 : // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13324 : // (mean_I(A) - mean_I(B)) *
13325 : // (mean_J(A) - mean_J(B)) *
13326 : // (count(A) * count(B)) / (count(A) + count(B))
13327 : //
13328 : // There might be a small gotcha in the fact that the set of
13329 : // pixels on which the means are computed is not always the
13330 : // same as the the one on which the comoment is computed, if
13331 : // pixels are not valid/invalid at the same indices among bands
13332 : // It is not obvious (to me) what should be the correct behavior.
13333 : // The current approach has the benefit to avoid recomputing
13334 : // the mean for each (i,j) tuple, but only for all i.
13335 500647 : if (nCount > 0)
13336 : {
13337 500639 : padfComomentMatrix[idxInMatrixI] +=
13338 : static_cast<double>(dfComoment);
13339 500639 : padfComomentMatrix[idxInMatrixI] +=
13340 500639 : static_cast<double>(adfMean[idxInMatrixI] -
13341 500639 : adfCurBlockMean[i]) *
13342 500639 : static_cast<double>(adfMean[idxInMatrixJ] -
13343 500639 : adfCurBlockMean[j]) *
13344 500639 : (static_cast<double>(anCount[idxInMatrixI]) *
13345 500639 : static_cast<double>(nCount) /
13346 500639 : static_cast<double>(anCount[idxInMatrixI] + nCount));
13347 :
13348 500639 : anCount[idxInMatrixI] += nCount;
13349 : }
13350 :
13351 : // Update means
13352 500647 : if (anCurBlockCount[i] > 0)
13353 : {
13354 1001280 : adfMean[idxInMatrixI] +=
13355 500640 : (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13356 : static_cast<T>(
13357 500640 : static_cast<double>(anCurBlockCount[i]) /
13358 500640 : static_cast<double>(anCountMean[idxInMatrixI] +
13359 : anCurBlockCount[i]));
13360 :
13361 500640 : anCountMean[idxInMatrixI] += anCurBlockCount[i];
13362 : }
13363 :
13364 500647 : if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13365 : {
13366 999132 : adfMean[idxInMatrixJ] +=
13367 499566 : (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13368 : static_cast<T>(
13369 499566 : static_cast<double>(anCurBlockCount[j]) /
13370 499566 : static_cast<double>(anCountMean[idxInMatrixJ] +
13371 : anCurBlockCount[j]));
13372 :
13373 499566 : anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13374 : }
13375 : };
13376 :
13377 32 : if (bAllBandsAreAllNodata)
13378 : {
13379 : // Optimized code path where all values in the current block
13380 : // are invalid
13381 :
13382 8 : for (int i = 0; i < nBandCount; ++i)
13383 : {
13384 12 : for (int j = i; j < nBandCount; ++j)
13385 : {
13386 7 : UpdateGlobalValues(i, j, 0, ZERO);
13387 : }
13388 : }
13389 : }
13390 29 : else if (bNoBandHasNodata)
13391 : {
13392 : // Optimized code path where there are no invalid value in the
13393 : // current block
13394 :
13395 : if constexpr (!std::is_same_v<T, double>)
13396 : {
13397 : std::fill(aCurBlockComomentMatrix.begin(),
13398 : aCurBlockComomentMatrix.end(), ZERO);
13399 :
13400 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13401 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13402 : aCurBlockComomentMatrix.data(), nBandCount,
13403 : nThisBlockPixelCount);
13404 : }
13405 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13406 24 : else if (bHasAVX2_FMA)
13407 : {
13408 24 : GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13409 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13410 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13411 : }
13412 : #endif
13413 : else
13414 : {
13415 0 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13416 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13417 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13418 : }
13419 :
13420 1088 : for (int i = 0; i < nBandCount; ++i)
13421 : {
13422 501689 : for (int j = i; j < nBandCount; ++j)
13423 : {
13424 : if constexpr (!std::is_same_v<T, double>)
13425 : {
13426 : const auto idxInMatrixI =
13427 : static_cast<size_t>(i) * nBandCount + j;
13428 : UpdateGlobalValues(
13429 : i, j, nThisBlockPixelCount,
13430 : aCurBlockComomentMatrix[idxInMatrixI]);
13431 : }
13432 : else
13433 : {
13434 500625 : UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13435 : }
13436 : }
13437 : }
13438 : }
13439 : else
13440 : {
13441 : #ifdef HAVE_OPENMP
13442 5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
13443 : #endif
13444 : for (MySignedSize_t k = 0; k < kMax; ++k)
13445 : {
13446 : int i, j;
13447 : std::tie(i, j) = anMapLinearIdxToIJ[k];
13448 :
13449 : // Now compute the moment of (i, j), but just for this block
13450 : size_t nCount = 0;
13451 : T dfComoment = 0;
13452 : const T *padfI =
13453 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13454 : const T *padfJ =
13455 : adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13456 :
13457 : // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13458 : // for the current block
13459 : if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13460 : anCurBlockCount[j] == nThisBlockPixelCount) ||
13461 : (bNoneHasMaskOrNodata && bIsAllInteger))
13462 : {
13463 : // Most optimized code path: integer, no nodata, no mask
13464 : #ifdef HAVE_OPENMP_SIMD
13465 : #pragma omp simd reduction(+ : dfComoment)
13466 : #endif
13467 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13468 : ++iPixel)
13469 : {
13470 : dfComoment += padfI[iPixel] * padfJ[iPixel];
13471 : }
13472 : nCount = nThisBlockPixelCount;
13473 : }
13474 : else if (bNoneHasMaskOrNodata)
13475 : {
13476 : // Floating-point code path with no nodata and no mask
13477 : #ifdef HAVE_OPENMP_SIMD
13478 : #pragma omp simd reduction(+ : dfComoment)
13479 : #endif
13480 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13481 : ++iPixel)
13482 : {
13483 : const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13484 : const bool bIsValid = !std::isnan(dfAcc);
13485 : nCount += bIsValid;
13486 : dfComoment += bIsValid ? dfAcc : ZERO;
13487 : }
13488 : }
13489 : else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13490 : {
13491 : // Code path when there are both nodata values
13492 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13493 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13494 :
13495 : #ifdef HAVE_OPENMP_SIMD
13496 : #pragma omp simd reduction(+ : dfComoment)
13497 : #endif
13498 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13499 : ++iPixel)
13500 : {
13501 : const T dfI = padfI[iPixel];
13502 : const T dfJ = padfJ[iPixel];
13503 : const T dfAcc = dfI * dfJ;
13504 : const bool bIsValid = !std::isnan(dfAcc) &&
13505 : dfI != shiftedNoDataI &&
13506 : dfJ != shiftedNoDataJ;
13507 : nCount += bIsValid;
13508 : dfComoment += bIsValid ? dfAcc : ZERO;
13509 : }
13510 : }
13511 : else
13512 : {
13513 : // Generic code path
13514 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13515 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13516 :
13517 : #ifdef HAVE_OPENMP_SIMD
13518 : #pragma omp simd reduction(+ : dfComoment)
13519 : #endif
13520 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13521 : ++iPixel)
13522 : {
13523 : const T dfI = padfI[iPixel];
13524 : const T dfJ = padfJ[iPixel];
13525 : const T dfAcc = dfI * dfJ;
13526 : const bool bIsValid =
13527 : !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13528 : dfJ != shiftedNoDataJ &&
13529 : (!pabyCurBlockMask[i] ||
13530 : (*pabyCurBlockMask[i])[iPixel]) &&
13531 : (!pabyCurBlockMask[j] ||
13532 : (*pabyCurBlockMask[j])[iPixel]);
13533 : nCount += bIsValid;
13534 : dfComoment += bIsValid ? dfAcc : ZERO;
13535 : }
13536 : }
13537 :
13538 : UpdateGlobalValues(i, j, nCount, dfComoment);
13539 : }
13540 : }
13541 :
13542 32 : ++nCurIter;
13543 35 : if (pfnProgress &&
13544 3 : !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13545 : pProgressData))
13546 : {
13547 1 : poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13548 : "User terminated");
13549 1 : return CE_Failure;
13550 : }
13551 : }
13552 :
13553 : // Finalize by dividing co-moments by the number of contributing values
13554 : // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13555 44 : for (int i = 0; i < nBandCount; ++i)
13556 : {
13557 : // The covariance matrix is symmetric. So start at i
13558 81 : for (int j = i; j < nBandCount; ++j)
13559 : {
13560 51 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13561 51 : const double dfCovariance =
13562 51 : (nDeltaDegreeOfFreedom < 0 ||
13563 51 : anCount[idxInMatrixI] <=
13564 51 : static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13565 4 : ? std::numeric_limits<double>::quiet_NaN()
13566 94 : : padfComomentMatrix[idxInMatrixI] /
13567 47 : static_cast<double>(anCount[idxInMatrixI] -
13568 47 : nDeltaDegreeOfFreedom);
13569 :
13570 51 : padfCovMatrix[idxInMatrixI] = dfCovariance;
13571 : // Fill lower triangle
13572 51 : padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13573 : dfCovariance;
13574 : }
13575 : }
13576 :
13577 14 : return CE_None;
13578 : }
13579 :
13580 : /************************************************************************/
13581 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
13582 : /************************************************************************/
13583 :
13584 : /**
13585 : \brief Compute the covariance matrix between bands of this dataset.
13586 :
13587 : The covariance indicates the level to which two bands vary together.
13588 :
13589 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13590 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13591 :
13592 : \f[
13593 : \mathrm{cov}[i,j] =
13594 : \frac{
13595 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13596 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13597 : }{
13598 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13599 : }
13600 : \f]
13601 :
13602 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13603 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13604 : is symmetric.
13605 :
13606 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13607 : if the pixels in bands are considered to be a sample of the whole population.
13608 : This is consistent with the default of
13609 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13610 : matrix is consistent with what can be obtained with
13611 :
13612 : \verbatim embed:rst
13613 : .. code-block:: python
13614 :
13615 : numpy.cov(
13616 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13617 : )
13618 : \endverbatim
13619 :
13620 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13621 : to be the whole population.
13622 :
13623 : The caller must provide an already allocated array in padfCovMatrix of size
13624 : at least nBandCount * nBandCount.
13625 :
13626 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13627 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
13628 : to use them.
13629 :
13630 : The implementation is optimized to minimize the amount of pixel reading.
13631 :
13632 : This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13633 :
13634 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13635 : nBandCount * nBandCount.
13636 : @param nSize Number of elements in output array.
13637 : @param nBandCount Zero for all bands, or number of values in panBandList.
13638 : Defaults to 0.
13639 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13640 : nBandCount values such as panBandList[i] is the index
13641 : between 1 and GetRasterCount() of a band that must be used
13642 : in the covariance computation. Defaults to nullptr.
13643 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13644 : Defaults to false.
13645 : @param bWriteIntoMetadata Whether this method must write
13646 : STATISTICS_COVARIANCES band metadata items.
13647 : Defaults to true.
13648 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13649 : averaging phase of the covariance computation.
13650 : Defaults to 1.
13651 : @param pfnProgress a function to call to report progress, or NULL.
13652 : @param pProgressData application data to pass to the progress function.
13653 :
13654 : @return CE_None if successful, or CE_Failure in case of failure
13655 :
13656 : @since 3.13
13657 :
13658 : @see GetInterBandCovarianceMatrix()
13659 : */
13660 22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13661 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13662 : bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13663 : GDALProgressFunc pfnProgress, void *pProgressData)
13664 : {
13665 44 : std::vector<int> anBandListTmp; // keep in this scope
13666 22 : if (nBandCount == 0)
13667 : {
13668 0 : if (nBands == 0)
13669 0 : return CE_None;
13670 0 : for (int i = 0; i < nBands; ++i)
13671 0 : anBandListTmp.push_back(i + 1);
13672 0 : nBandCount = nBands;
13673 0 : panBandList = anBandListTmp.data();
13674 : }
13675 : else
13676 : {
13677 22 : if (nBandCount > nBands)
13678 : {
13679 1 : CPLError(CE_Failure, CPLE_AppDefined,
13680 : "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13681 1 : return CE_Failure;
13682 : }
13683 1057 : for (int i = 0; i < nBandCount; ++i)
13684 : {
13685 1038 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
13686 : {
13687 2 : CPLError(CE_Failure, CPLE_AppDefined,
13688 : "ComputeInterBandCovarianceMatrix(): invalid value "
13689 : "panBandList[%d] = %d",
13690 2 : i, panBandList[i]);
13691 2 : return CE_Failure;
13692 : }
13693 : }
13694 :
13695 19 : if (bWriteIntoMetadata)
13696 : {
13697 14 : bool bOK = nBandCount == nBands;
13698 38 : for (int i = 0; bOK && i < nBandCount; ++i)
13699 : {
13700 24 : bOK = (panBandList[i] == i + 1);
13701 : }
13702 14 : if (!bOK)
13703 : {
13704 4 : CPLError(CE_Failure, CPLE_AppDefined,
13705 : "ComputeInterBandCovarianceMatrix(): cannot write "
13706 : "STATISTICS_COVARIANCES metadata since the input band "
13707 : "list is not [1, 2, ... GetRasterCount()]");
13708 4 : return CE_Failure;
13709 : }
13710 : }
13711 : }
13712 :
13713 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13714 15 : if (nSize < nMatrixSize)
13715 : {
13716 0 : CPLError(CE_Failure, CPLE_AppDefined,
13717 : "ComputeInterBandCovarianceMatrix(): too small result matrix "
13718 : "provided");
13719 0 : return CE_Failure;
13720 : }
13721 :
13722 : // Find appropriate overview dataset
13723 15 : GDALDataset *poActiveDS = this;
13724 15 : if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13725 : {
13726 1 : GDALDataset *poOvrDS = nullptr;
13727 4 : for (int i = 0; i < nBandCount; ++i)
13728 : {
13729 3 : const int nIdxBand = panBandList[i] - 1;
13730 6 : auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13731 3 : GDALSTAT_APPROX_NUMSAMPLES);
13732 :
13733 6 : if (poOvrBand == papoBands[i] ||
13734 3 : poOvrBand->GetBand() != panBandList[i])
13735 : {
13736 0 : poOvrDS = nullptr;
13737 0 : break;
13738 : }
13739 3 : else if (i == 0)
13740 : {
13741 1 : if (poOvrBand->GetDataset() == this)
13742 : {
13743 0 : break;
13744 : }
13745 1 : poOvrDS = poOvrBand->GetDataset();
13746 : }
13747 2 : else if (poOvrBand->GetDataset() != poOvrDS)
13748 : {
13749 0 : poOvrDS = nullptr;
13750 0 : break;
13751 : }
13752 : }
13753 1 : if (poOvrDS)
13754 : {
13755 1 : poActiveDS = poOvrDS;
13756 : }
13757 : }
13758 :
13759 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13760 : const auto UseFloat32 = [](GDALDataType eDT)
13761 : {
13762 : return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13763 : eDT == GDT_Int16 || eDT == GDT_Float32;
13764 : };
13765 :
13766 : bool bUseFloat32 = UseFloat32(
13767 : poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13768 : for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13769 : {
13770 : bUseFloat32 = UseFloat32(
13771 : poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13772 : }
13773 : #endif
13774 :
13775 : CPLErr eErr =
13776 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13777 : bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13778 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13779 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13780 : pfnProgress, pProgressData)
13781 : :
13782 : #endif
13783 30 : ComputeInterBandCovarianceMatrixInternal<double>(
13784 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13785 15 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13786 : pfnProgress, pProgressData);
13787 :
13788 15 : if (bWriteIntoMetadata && eErr == CE_None)
13789 : {
13790 10 : CPLAssert(nBands == nBandCount);
13791 20 : std::string osStr;
13792 10 : size_t idx = 0;
13793 32 : for (int i = 0; i < nBands; ++i)
13794 : {
13795 22 : osStr.clear();
13796 74 : for (int j = 0; j < nBands; ++j, ++idx)
13797 : {
13798 52 : if (j > 0)
13799 30 : osStr += ',';
13800 52 : osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13801 : }
13802 22 : papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13803 22 : osStr.c_str());
13804 : }
13805 : }
13806 :
13807 15 : return eErr;
13808 : }
13809 :
13810 : /************************************************************************/
13811 : /* GDALDatasetComputeInterBandCovarianceMatrix() */
13812 : /************************************************************************/
13813 :
13814 : /**
13815 : \brief Compute the covariance matrix between bands of this dataset.
13816 :
13817 : The covariance indicates the level to which two bands vary together.
13818 :
13819 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13820 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13821 :
13822 : \f[
13823 : \mathrm{cov}[i,j] =
13824 : \frac{
13825 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13826 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13827 : }{
13828 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13829 : }
13830 : \f]
13831 :
13832 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13833 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13834 : is symmetric.
13835 :
13836 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13837 : if the pixels in bands are considered to be a sample of the whole population.
13838 : This is consistent with the default of
13839 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13840 : matrix is consistent with what can be obtained with
13841 :
13842 : \verbatim embed:rst
13843 : .. code-block:: python
13844 :
13845 : numpy.cov(
13846 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13847 : )
13848 : \endverbatim
13849 :
13850 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13851 : to be the whole population.
13852 :
13853 : The caller must provide an already allocated array in padfCovMatrix of size
13854 : at least GDALGetRasterCount() * GDALGetRasterCount().
13855 :
13856 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13857 : metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13858 : to use them.
13859 :
13860 : This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13861 :
13862 : @param hDS Dataset handle.
13863 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13864 : nBandCount * nBandCount.
13865 : @param nSize Number of elements in output array.
13866 : @param nBandCount Zero for all bands, or number of values in panBandList.
13867 : Defaults to 0.
13868 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13869 : nBandCount values such as panBandList[i] is the index
13870 : between 1 and GetRasterCount() of a band that must be used
13871 : in the covariance computation. Defaults to nullptr.
13872 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13873 : Defaults to false.
13874 : @param bWriteIntoMetadata Whether this method must write
13875 : STATISTICS_COVARIANCES band metadata items.
13876 : Defaults to true.
13877 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13878 : averaging phase of the covariance computation.
13879 : Defaults to 1.
13880 : @param pfnProgress a function to call to report progress, or NULL.
13881 : @param pProgressData application data to pass to the progress function.
13882 :
13883 : @return CE_None if successful, or CE_Failure in case of failure
13884 :
13885 : @since 3.13
13886 :
13887 : @see GDALDatasetGetInterBandCovarianceMatrix()
13888 : */
13889 17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13890 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13891 : const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13892 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13893 : void *pProgressData)
13894 : {
13895 17 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13896 17 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13897 17 : return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13898 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13899 17 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13900 : }
|