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 205890 : 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 8460 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
166 : {
167 8460 : const SharedDatasetCtxt *psStruct =
168 : static_cast<const SharedDatasetCtxt *>(elt);
169 : return static_cast<unsigned long>(
170 8460 : CPLHashSetHashStr(psStruct->pszDescription) ^
171 8460 : CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
172 8460 : psStruct->nOpenFlags ^ psStruct->nPID);
173 : }
174 :
175 7000 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
176 : {
177 7000 : const SharedDatasetCtxt *psStruct1 =
178 : static_cast<const SharedDatasetCtxt *>(elt1);
179 7000 : const SharedDatasetCtxt *psStruct2 =
180 : static_cast<const SharedDatasetCtxt *>(elt2);
181 13939 : return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
182 6939 : strcmp(psStruct1->pszConcatenatedOpenOptions,
183 6939 : psStruct2->pszConcatenatedOpenOptions) == 0 &&
184 20878 : psStruct1->nPID == psStruct2->nPID &&
185 13939 : 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 7075 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
198 : {
199 7075 : std::string osStr;
200 7088 : for (const char *pszOption : cpl::Iterate(papszOpenOptions))
201 13 : osStr += pszOption;
202 7075 : 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 488309 : CPLMutex **GDALGetphDLMutex()
211 : {
212 488309 : return &hDLMutex;
213 : }
214 :
215 : // The current thread will act in the behalf of the thread of PID
216 : // responsiblePID.
217 476775 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
218 : {
219 : GIntBig *pResponsiblePID =
220 476775 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
221 476775 : if (pResponsiblePID == nullptr)
222 : {
223 222 : pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
224 222 : CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
225 : }
226 476775 : *pResponsiblePID = responsiblePID;
227 476775 : }
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 614212 : GIntBig GDALGetResponsiblePIDForCurrentThread()
232 : {
233 : GIntBig *pResponsiblePID =
234 614212 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
235 614212 : if (pResponsiblePID == nullptr)
236 45546 : return CPLGetPID();
237 568666 : 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 170040 : GDALDataset::GDALDataset()
264 170040 : : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
265 : {
266 170040 : }
267 :
268 205890 : GDALDataset::GDALDataset(int bForceCachedIOIn)
269 205890 : : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
270 205890 : m_poPrivate(new (std::nothrow) GDALDataset::Private)
271 : {
272 205890 : }
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 205871 : 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 205871 : if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
301 : {
302 77126 : 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 76919 : CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
309 : }
310 :
311 205871 : GDALDataset::Close();
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Remove dataset from the "open" dataset list. */
315 : /* -------------------------------------------------------------------- */
316 205871 : if (!bIsInternal)
317 : {
318 157568 : CPLMutexHolderD(&hDLMutex);
319 78784 : if (poAllDatasetMap)
320 : {
321 : std::map<GDALDataset *, GIntBig>::iterator oIter =
322 78784 : poAllDatasetMap->find(this);
323 78784 : CPLAssert(oIter != poAllDatasetMap->end());
324 :
325 78784 : UnregisterFromSharedDataset();
326 :
327 78784 : poAllDatasetMap->erase(oIter);
328 :
329 78784 : if (poAllDatasetMap->empty())
330 : {
331 32731 : delete poAllDatasetMap;
332 32731 : poAllDatasetMap = nullptr;
333 32731 : if (phSharedDatasetSet)
334 : {
335 284 : CPLHashSetDestroy(phSharedDatasetSet);
336 : }
337 32731 : phSharedDatasetSet = nullptr;
338 32731 : CPLFree(ppDatasets);
339 32731 : ppDatasets = nullptr;
340 : }
341 : }
342 : }
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* Destroy the raster bands if they exist. */
346 : /* -------------------------------------------------------------------- */
347 1766500 : for (int i = 0; i < nBands && papoBands != nullptr; ++i)
348 : {
349 1560630 : if (papoBands[i] != nullptr)
350 1560630 : delete papoBands[i];
351 1560630 : papoBands[i] = nullptr;
352 : }
353 :
354 205871 : CPLFree(papoBands);
355 :
356 205871 : if (m_poStyleTable)
357 : {
358 23 : delete m_poStyleTable;
359 23 : m_poStyleTable = nullptr;
360 : }
361 :
362 205871 : if (m_poPrivate != nullptr)
363 : {
364 205871 : if (m_poPrivate->hMutex != nullptr)
365 22410 : 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 411742 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
370 : #endif
371 205871 : CPLFree(m_poPrivate->m_pszWKTCached);
372 205871 : if (m_poPrivate->m_poSRSCached)
373 : {
374 0 : m_poPrivate->m_poSRSCached->Release();
375 : }
376 205871 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
377 205871 : if (m_poPrivate->m_poSRSGCPCached)
378 : {
379 0 : m_poPrivate->m_poSRSGCPCached->Release();
380 : }
381 : }
382 :
383 205871 : delete m_poPrivate;
384 :
385 205871 : CSLDestroy(papszOpenOptions);
386 205871 : }
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 341737 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
474 : {
475 : (void)pfnProgress;
476 : (void)pProgressData;
477 :
478 341737 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
479 : {
480 : // Call UnregisterFromSharedDataset() before altering nOpenFlags
481 205871 : UnregisterFromSharedDataset();
482 :
483 205871 : nOpenFlags = OPEN_FLAGS_CLOSED;
484 : }
485 :
486 341737 : if (IsMarkedSuppressOnClose())
487 : {
488 3570 : 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 1739 : (!EQUAL(poDriver->GetDescription(), "MEM") &&
495 1661 : !EQUAL(poDriver->GetDescription(), "Memory")))
496 : {
497 1753 : if (VSIUnlink(GetDescription()) == 0)
498 683 : UnMarkSuppressOnClose();
499 : }
500 : }
501 :
502 341737 : 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 13 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
569 : GDALProgressFunc pfnProgress,
570 : void *pProgressData)
571 : {
572 13 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
573 13 : return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
574 : }
575 :
576 : /************************************************************************/
577 : /* GetCloseReportsProgress() */
578 : /************************************************************************/
579 :
580 : /** Returns whether the Close() operation will report progress / is a potential
581 : * lengthy operation.
582 : *
583 : * At time of writing, only the COG driver will return true, if the dataset
584 : * has been created through the GDALDriver::Create() interface.
585 : *
586 : * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
587 : *
588 : * @return true if the Close() operation will report progress
589 : * @since GDAL 3.13
590 : * @see Close()
591 : */
592 243 : bool GDALDataset::GetCloseReportsProgress() const
593 : {
594 243 : return false;
595 : }
596 :
597 : /************************************************************************/
598 : /* GDALDatasetGetCloseReportsProgress() */
599 : /************************************************************************/
600 :
601 : /** Returns whether the Close() operation will report progress / is a potential
602 : * lengthy operation.
603 : *
604 : * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
605 : *
606 : * @param hDS dataset handle.
607 : * @return CE_None if no error
608 : *
609 : * @return true if the Close() operation will report progress
610 : * @since GDAL 3.13
611 : * @see GDALClose()
612 : */
613 2 : bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
614 : {
615 2 : VALIDATE_POINTER1(hDS, __func__, false);
616 2 : return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
617 : }
618 :
619 : /************************************************************************/
620 : /* CanReopenWithCurrentDescription() */
621 : /************************************************************************/
622 :
623 : /** Returns whether, once this dataset is closed, it can be re-opened with
624 : * Open() using the current value of GetDescription()
625 : *
626 : * The default implementation returns true. Some drivers, like MVT in Create()
627 : * mode, can return false. Some drivers return true, but the re-opened dataset
628 : * may be opened by another driver (e.g. the COG driver will return true, but
629 : * the driver used for re-opening is GTiff).
630 : *
631 : * @return true if the dataset can be re-opened using the value as
632 : * GetDescription() as connection string for Open()
633 : * @since GDAL 3.13
634 : */
635 2 : bool GDALDataset::CanReopenWithCurrentDescription() const
636 : {
637 2 : return true;
638 : }
639 :
640 : /************************************************************************/
641 : /* UnregisterFromSharedDataset() */
642 : /************************************************************************/
643 :
644 284655 : void GDALDataset::UnregisterFromSharedDataset()
645 : {
646 284655 : if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
647 284238 : 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 80101 : void GDALDataset::AddToDatasetOpenList()
684 : {
685 : /* -------------------------------------------------------------------- */
686 : /* Add this dataset to the open dataset list. */
687 : /* -------------------------------------------------------------------- */
688 80101 : bIsInternal = false;
689 :
690 80101 : CPLMutexHolderD(&hDLMutex);
691 :
692 80101 : if (poAllDatasetMap == nullptr)
693 32741 : poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
694 80101 : (*poAllDatasetMap)[this] = -1;
695 80101 : }
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 141964 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
724 :
725 : {
726 141964 : CPLErr eErr = CE_None;
727 : // This sometimes happens if a dataset is destroyed before completely
728 : // built.
729 :
730 141964 : if (papoBands)
731 : {
732 1981920 : for (int i = 0; i < nBands; ++i)
733 : {
734 1855610 : if (papoBands[i])
735 : {
736 1855610 : if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
737 7 : eErr = CE_Failure;
738 : }
739 : }
740 : }
741 :
742 141964 : const int nLayers = GetLayerCount();
743 : // cppcheck-suppress knownConditionTrueFalse
744 141964 : if (nLayers > 0)
745 : {
746 18014 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
747 27513 : for (int i = 0; i < nLayers; ++i)
748 : {
749 18506 : OGRLayer *poLayer = GetLayer(i);
750 :
751 18506 : if (poLayer)
752 : {
753 18506 : if (poLayer->SyncToDisk() != OGRERR_NONE)
754 1 : eErr = CE_Failure;
755 : }
756 : }
757 : }
758 :
759 141964 : 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 5297 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
774 :
775 : {
776 5297 : VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
777 :
778 5297 : 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 3427 : GIntBig GDALDataset::GetEstimatedRAMUsage()
860 : {
861 3427 : 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 1706100 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1007 :
1008 : {
1009 : /* -------------------------------------------------------------------- */
1010 : /* Do we need to grow the bands list? */
1011 : /* -------------------------------------------------------------------- */
1012 1706100 : if (nBands < nNewBand || papoBands == nullptr)
1013 : {
1014 970311 : GDALRasterBand **papoNewBands = nullptr;
1015 :
1016 970311 : if (papoBands == nullptr)
1017 117659 : papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1018 117659 : sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1019 : else
1020 : papoNewBands = static_cast<GDALRasterBand **>(
1021 852652 : VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1022 852652 : std::max(nNewBand, nBands)));
1023 970311 : if (papoNewBands == nullptr)
1024 : {
1025 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1026 : "Cannot allocate band array");
1027 0 : return;
1028 : }
1029 :
1030 970311 : papoBands = papoNewBands;
1031 :
1032 1886760 : for (int i = nBands; i < nNewBand; ++i)
1033 916452 : papoBands[i] = nullptr;
1034 :
1035 970311 : nBands = std::max(nBands, nNewBand);
1036 :
1037 970311 : if (m_poPrivate)
1038 : {
1039 970311 : for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1040 2676410 : i < nBands; ++i)
1041 : {
1042 1706100 : 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 1706100 : 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 1706100 : 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 1706100 : poBand->nBand = nNewBand;
1065 1706100 : poBand->poDS = this;
1066 1706100 : poBand->nRasterXSize = nRasterXSize;
1067 1706100 : poBand->nRasterYSize = nRasterYSize;
1068 1706100 : 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 1112800 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1086 : {
1087 1112800 : SetBand(nNewBand, poBand.release());
1088 1112800 : }
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 743466 : int GDALDataset::GetRasterXSize() const
1107 : {
1108 743466 : 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 40602 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1122 :
1123 : {
1124 40602 : VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1125 :
1126 40602 : 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 622766 : int GDALDataset::GetRasterYSize() const
1144 : {
1145 622766 : 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 39814 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1159 :
1160 : {
1161 39814 : VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1162 :
1163 39814 : 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 12494400 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1186 :
1187 : {
1188 12494400 : if (papoBands)
1189 : {
1190 12494400 : 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 12494400 : return papoBands[nBandId - 1];
1199 : }
1200 13 : return nullptr;
1201 : }
1202 :
1203 : /************************************************************************/
1204 : /* GetRasterBand() */
1205 : /************************************************************************/
1206 :
1207 : /**
1208 :
1209 : \brief Fetch a band object for a dataset.
1210 :
1211 : See GetBands() for a C++ iterator version of this method.
1212 :
1213 : Equivalent of the C function GDALGetRasterBand().
1214 :
1215 : @param nBandId the index number of the band to fetch, from 1 to
1216 : GetRasterCount().
1217 :
1218 : @return the nBandId th band object
1219 :
1220 : */
1221 :
1222 594 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1223 :
1224 : {
1225 594 : if (papoBands)
1226 : {
1227 594 : if (nBandId < 1 || nBandId > nBands)
1228 : {
1229 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1230 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1231 : nBandId);
1232 0 : return nullptr;
1233 : }
1234 :
1235 594 : return papoBands[nBandId - 1];
1236 : }
1237 0 : return nullptr;
1238 : }
1239 :
1240 : /************************************************************************/
1241 : /* GDALGetRasterBand() */
1242 : /************************************************************************/
1243 :
1244 : /**
1245 : * \brief Fetch a band object for a dataset.
1246 : * @see GDALDataset::GetRasterBand().
1247 : */
1248 :
1249 414442 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1250 :
1251 : {
1252 414442 : VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1253 :
1254 414442 : return GDALRasterBand::ToHandle(
1255 414442 : 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 6263540 : int GDALDataset::GetRasterCount() const
1271 : {
1272 6263540 : 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 388295 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1286 :
1287 : {
1288 388295 : VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1289 :
1290 388295 : 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 5264 : const char *GDALDataset::GetProjectionRef() const
1319 : {
1320 5264 : const auto poSRS = GetSpatialRef();
1321 5264 : if (!poSRS || !m_poPrivate)
1322 : {
1323 2379 : return "";
1324 : }
1325 2885 : char *pszWKT = nullptr;
1326 2885 : poSRS->exportToWkt(&pszWKT);
1327 2885 : 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 5770 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1336 2885 : 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 2134 : CPLFree(m_poPrivate->m_pszWKTCached);
1343 2134 : m_poPrivate->m_pszWKTCached = pszWKT;
1344 2134 : 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 17954 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1375 : {
1376 17954 : if (tlsEnableLayersInGetSpatialRefCounter == 0)
1377 17909 : 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 17909 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1399 : {
1400 17909 : bool bInit = false;
1401 17909 : const OGRSpatialReference *poGlobalSRS = nullptr;
1402 34082 : for (const OGRLayer *poLayer : GetLayers())
1403 : {
1404 16166 : for (const auto *poGeomFieldDefn :
1405 48508 : poLayer->GetLayerDefn()->GetGeomFields())
1406 : {
1407 16169 : const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1408 16169 : if (!bInit)
1409 : {
1410 209 : bInit = true;
1411 209 : poGlobalSRS = poSRS;
1412 : }
1413 31918 : else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1414 15958 : (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1415 : {
1416 3 : CPLDebug("GDAL",
1417 : "Not all geometry fields or layers have the same CRS");
1418 3 : return nullptr;
1419 : }
1420 : }
1421 : }
1422 17906 : 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 1084 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1439 : {
1440 1084 : ++tlsEnableLayersInGetSpatialRefCounter;
1441 1084 : const auto poRet = GetSpatialRef();
1442 1084 : --tlsEnableLayersInGetSpatialRefCounter;
1443 1084 : 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 8245 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1461 :
1462 : {
1463 8245 : VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1464 :
1465 8245 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1466 8245 : 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 1454 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1480 :
1481 : {
1482 1454 : VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1483 :
1484 1454 : 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 2603 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
1510 : {
1511 2603 : if (pszProjection && pszProjection[0] != '\0')
1512 : {
1513 4822 : OGRSpatialReference oSRS;
1514 2411 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1515 2411 : if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1516 : {
1517 2 : return CE_Failure;
1518 : }
1519 2409 : return SetSpatialRef(&oSRS);
1520 : }
1521 : else
1522 : {
1523 192 : return SetSpatialRef(nullptr);
1524 : }
1525 : }
1526 :
1527 : /************************************************************************/
1528 : /* SetSpatialRef() */
1529 : /************************************************************************/
1530 :
1531 : /**
1532 : * \brief Set the spatial reference system for this dataset.
1533 : *
1534 : * An error may occur because the dataset
1535 : * is not writable, or because the dataset does not support the indicated
1536 : * projection. Many formats do not support writing projections.
1537 : *
1538 : * This method is the same as the C GDALSetSpatialRef() function.
1539 : *
1540 : * @since GDAL 3.0
1541 :
1542 : * @param poSRS spatial reference system object. nullptr can potentially be
1543 : * passed for drivers that support unsetting the SRS.
1544 : *
1545 : * @return CE_Failure if an error occurs, otherwise CE_None.
1546 : */
1547 :
1548 0 : CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1549 : {
1550 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1551 0 : ReportError(CE_Failure, CPLE_NotSupported,
1552 : "Dataset does not support the SetSpatialRef() method.");
1553 0 : return CE_Failure;
1554 : }
1555 :
1556 : /************************************************************************/
1557 : /* GDALSetSpatialRef() */
1558 : /************************************************************************/
1559 :
1560 : /**
1561 : * \brief Set the spatial reference system for this dataset.
1562 : *
1563 : * @since GDAL 3.0
1564 : *
1565 : * @see GDALDataset::SetSpatialRef()
1566 : */
1567 :
1568 1514 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1569 :
1570 : {
1571 1514 : VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1572 :
1573 3028 : return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1574 1514 : 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 1942 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1588 : const char *pszProjection)
1589 :
1590 : {
1591 1942 : VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1592 :
1593 1942 : 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 16309 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform >) const
1630 :
1631 : {
1632 16309 : gt = GDALGeoTransform();
1633 :
1634 16309 : 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 9823 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1688 :
1689 : {
1690 9823 : VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1691 :
1692 19646 : return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1693 9823 : *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 4560 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1765 : const double *padfTransform)
1766 :
1767 : {
1768 4560 : VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1769 4560 : VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1770 :
1771 9120 : return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1772 4560 : *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 169 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1792 :
1793 : {
1794 169 : 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 36909 : GDALDriver *GDALDataset::GetDriver() const
1830 : {
1831 36909 : return poDriver;
1832 : }
1833 :
1834 : /************************************************************************/
1835 : /* GDALGetDatasetDriver() */
1836 : /************************************************************************/
1837 :
1838 : /**
1839 : * \brief Fetch the driver to which this dataset relates.
1840 : *
1841 : * @see GDALDataset::GetDriver()
1842 : */
1843 :
1844 2827 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1845 :
1846 : {
1847 2827 : VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1848 :
1849 : return static_cast<GDALDriverH>(
1850 2827 : GDALDataset::FromHandle(hDataset)->GetDriver());
1851 : }
1852 :
1853 : /************************************************************************/
1854 : /* Reference() */
1855 : /************************************************************************/
1856 :
1857 : /**
1858 : * \brief Add one to dataset reference count.
1859 : *
1860 : * The reference is one after instantiation.
1861 : *
1862 : * This method is the same as the C GDALReferenceDataset() function.
1863 : *
1864 : * @return the post-increment reference count.
1865 : */
1866 :
1867 264722 : int GDALDataset::Reference()
1868 : {
1869 264722 : 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 1508 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1883 :
1884 : {
1885 1508 : VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1886 :
1887 1508 : 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 329530 : int GDALDataset::Dereference()
1906 : {
1907 329530 : 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 62471 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1921 :
1922 : {
1923 62471 : VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1924 :
1925 62471 : 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 253783 : int GDALDataset::ReleaseRef()
1938 :
1939 : {
1940 253783 : if (Dereference() <= 0)
1941 : {
1942 7970 : nRefCount = 1;
1943 7970 : delete this;
1944 7970 : return TRUE;
1945 : }
1946 245813 : 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 1693 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1960 :
1961 : {
1962 1693 : VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1963 :
1964 1693 : 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 326931 : int GDALDataset::GetShared() const
1978 : {
1979 326931 : 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 286 : phSharedDatasetSet =
2005 286 : 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 1261 : void GDALDataset::MarkSuppressOnClose()
2042 : {
2043 1261 : bSuppressOnClose = true;
2044 1261 : }
2045 :
2046 : /************************************************************************/
2047 : /* GDALDatasetMarkSuppressOnClose() */
2048 : /************************************************************************/
2049 :
2050 : /** Set that the dataset must be deleted on close.
2051 : *
2052 : * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2053 : *
2054 : * @since GDAL 3.12
2055 : */
2056 :
2057 4 : void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2058 : {
2059 4 : VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2060 :
2061 4 : return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2062 : }
2063 :
2064 : /************************************************************************/
2065 : /* UnMarkSuppressOnClose() */
2066 : /************************************************************************/
2067 :
2068 : /** Remove the flag requesting the dataset to be deleted on close. */
2069 684 : void GDALDataset::UnMarkSuppressOnClose()
2070 : {
2071 684 : bSuppressOnClose = false;
2072 684 : }
2073 :
2074 : /************************************************************************/
2075 : /* CleanupPostFileClosing() */
2076 : /************************************************************************/
2077 :
2078 : /** This method should be called by driver implementations in their destructor,
2079 : * after having closed all files, but before having freed resources that
2080 : * are needed for their GetFileList() implementation.
2081 : * This is used to implement MarkSuppressOnClose behavior.
2082 : */
2083 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 16814 : int GDALDataset::GetGCPCount()
2107 : {
2108 16814 : return 0;
2109 : }
2110 :
2111 : /************************************************************************/
2112 : /* GDALGetGCPCount() */
2113 : /************************************************************************/
2114 :
2115 : /**
2116 : * \brief Get number of GCPs.
2117 : *
2118 : * @see GDALDataset::GetGCPCount()
2119 : */
2120 :
2121 2318 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2122 :
2123 : {
2124 2318 : VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2125 :
2126 2318 : return GDALDataset::FromHandle(hDS)->GetGCPCount();
2127 : }
2128 :
2129 : /************************************************************************/
2130 : /* GetGCPProjection() */
2131 : /************************************************************************/
2132 :
2133 : /**
2134 : * \brief Get output projection for GCPs.
2135 : *
2136 : * This method is the same as the C function GDALGetGCPProjection().
2137 : *
2138 : * The projection string follows the normal rules from GetProjectionRef().
2139 : *
2140 : * \note Starting with GDAL 3.0, this is a compatibility layer around
2141 : * GetGCPSpatialRef()
2142 : *
2143 : * @return internal projection string or "" if there are no GCPs.
2144 : * It should not be altered, freed or expected to last for long.
2145 : */
2146 :
2147 1055 : const char *GDALDataset::GetGCPProjection() const
2148 : {
2149 1055 : const auto poSRS = GetGCPSpatialRef();
2150 1055 : if (!poSRS || !m_poPrivate)
2151 : {
2152 717 : return "";
2153 : }
2154 338 : char *pszWKT = nullptr;
2155 338 : poSRS->exportToWkt(&pszWKT);
2156 338 : if (!pszWKT)
2157 : {
2158 0 : return "";
2159 : }
2160 :
2161 : // If called on a thread-safe dataset, we might be called by several
2162 : // threads, so make sure our accesses to m_pszWKTCached are protected
2163 : // by a mutex.
2164 676 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2165 338 : if (m_poPrivate->m_pszWKTGCPCached &&
2166 258 : strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2167 : {
2168 258 : CPLFree(pszWKT);
2169 258 : return m_poPrivate->m_pszWKTGCPCached;
2170 : }
2171 80 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
2172 80 : m_poPrivate->m_pszWKTGCPCached = pszWKT;
2173 80 : return m_poPrivate->m_pszWKTGCPCached;
2174 : }
2175 :
2176 : /************************************************************************/
2177 : /* GetGCPSpatialRef() */
2178 : /************************************************************************/
2179 :
2180 : /**
2181 : * \brief Get output spatial reference system for GCPs.
2182 : *
2183 : * Same as the C function GDALGetGCPSpatialRef().
2184 : *
2185 : * When a SRS is not available, null is returned. If used on
2186 : * a dataset where there is a geotransform, and not GCPs, this method returns
2187 : * null. Use GetSpatialRef() instead.
2188 : *
2189 : * @since GDAL 3.0
2190 : *
2191 : * @return a pointer to an internal object. It should not be altered or freed.
2192 : * Its lifetime will be the one of the dataset object, or until the next
2193 : * call to this method.
2194 : */
2195 :
2196 47 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2197 : {
2198 47 : return nullptr;
2199 : }
2200 :
2201 : /************************************************************************/
2202 : /* GDALGetGCPSpatialRef() */
2203 : /************************************************************************/
2204 :
2205 : /**
2206 : * \brief Get output spatial reference system for GCPs.
2207 : *
2208 : * @since GDAL 3.0
2209 : *
2210 : * @see GDALDataset::GetGCPSpatialRef()
2211 : */
2212 :
2213 472 : OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2214 :
2215 : {
2216 472 : VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2217 :
2218 472 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2219 472 : GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2220 : }
2221 :
2222 : /************************************************************************/
2223 : /* GDALGetGCPProjection() */
2224 : /************************************************************************/
2225 :
2226 : /**
2227 : * \brief Get output projection for GCPs.
2228 : *
2229 : * @see GDALDataset::GetGCPProjection()
2230 : */
2231 :
2232 1034 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2233 :
2234 : {
2235 1034 : VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2236 :
2237 1034 : 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 760 : 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 760 : int *panAllBandList = nullptr;
2474 :
2475 1520 : CPLStringList aosOptions(papszOptions);
2476 760 : 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 760 : if (nListBands == 0)
2526 : {
2527 748 : nListBands = GetRasterCount();
2528 : panAllBandList =
2529 748 : static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2530 67499 : for (int i = 0; i < nListBands; ++i)
2531 66751 : panAllBandList[i] = i + 1;
2532 :
2533 748 : panBandList = panAllBandList;
2534 : }
2535 :
2536 760 : if (pfnProgress == nullptr)
2537 725 : pfnProgress = GDALDummyProgress;
2538 :
2539 1854 : for (int i = 0; i < nOverviews; ++i)
2540 : {
2541 1095 : 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 759 : const CPLErr eErr = IBuildOverviews(
2553 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2554 759 : pfnProgress, pProgressData, aosOptions.List());
2555 :
2556 759 : if (panAllBandList != nullptr)
2557 746 : CPLFree(panAllBandList);
2558 :
2559 759 : 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 709 : 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 709 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2606 :
2607 709 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2608 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2609 709 : pfnProgress, pProgressData, papszOptions);
2610 : }
2611 :
2612 : /************************************************************************/
2613 : /* IBuildOverviews() */
2614 : /* */
2615 : /* Default implementation. */
2616 : /************************************************************************/
2617 :
2618 : //! @cond Doxygen_Suppress
2619 198 : 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 198 : if (oOvManager.IsInitialized())
2628 197 : return oOvManager.BuildOverviews(
2629 : nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2630 197 : 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 451960 : 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 451960 : const char *pszInterleave = nullptr;
2712 :
2713 451960 : CPLAssert(nullptr != pData);
2714 :
2715 451960 : const bool bHasSubpixelShift =
2716 459151 : psExtraArg->bFloatingPointWindowValidity &&
2717 457505 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2718 5545 : (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2719 :
2720 451841 : if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2721 72543 : nBandCount > 1 &&
2722 72543 : (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2723 903801 : nullptr &&
2724 69342 : EQUAL(pszInterleave, "PIXEL"))
2725 : {
2726 65920 : return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2727 : nBufXSize, nBufYSize, eBufType, nBandCount,
2728 : panBandMap, nPixelSpace, nLineSpace,
2729 65920 : nBandSpace, psExtraArg);
2730 : }
2731 :
2732 386040 : if (eRWFlag == GF_Read &&
2733 206422 : (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2734 205627 : psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2735 205614 : psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2736 206422 : 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 383565 : return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2874 : nBufXSize, nBufYSize, eBufType, nBandCount,
2875 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2876 383565 : 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 661568 : 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 661568 : CPLErr eErr = CE_None;
2898 :
2899 661568 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2900 661568 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2901 :
2902 1724300 : for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2903 : ++iBandIndex)
2904 : {
2905 1062740 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2906 :
2907 1062740 : if (poBand == nullptr)
2908 : {
2909 0 : eErr = CE_Failure;
2910 0 : break;
2911 : }
2912 :
2913 1062740 : GByte *pabyBandData =
2914 1062740 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2915 :
2916 1062740 : if (nBandCount > 1)
2917 : {
2918 591020 : psExtraArg->pfnProgress = GDALScaledProgress;
2919 1182040 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2920 : 1.0 * iBandIndex / nBandCount,
2921 591020 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2922 : pProgressDataGlobal);
2923 591020 : if (psExtraArg->pProgressData == nullptr)
2924 577421 : psExtraArg->pfnProgress = nullptr;
2925 : }
2926 :
2927 2125470 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2928 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2929 1062740 : nPixelSpace, nLineSpace, psExtraArg);
2930 :
2931 1062740 : if (nBandCount > 1)
2932 591020 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2933 : }
2934 :
2935 661568 : psExtraArg->pfnProgress = pfnProgressGlobal;
2936 661568 : psExtraArg->pProgressData = pProgressDataGlobal;
2937 :
2938 661568 : return eErr;
2939 : }
2940 :
2941 : //! @endcond
2942 :
2943 : /************************************************************************/
2944 : /* ValidateRasterIOOrAdviseReadParameters() */
2945 : /************************************************************************/
2946 :
2947 : //! @cond Doxygen_Suppress
2948 770144 : 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 770144 : if (nBands == 0)
2954 : {
2955 138 : *pbStopProcessingOnCENone = TRUE;
2956 138 : return CE_None;
2957 : }
2958 :
2959 : /* -------------------------------------------------------------------- */
2960 : /* Some size values are "noop". Lets just return to avoid */
2961 : /* stressing lower level functions. */
2962 : /* -------------------------------------------------------------------- */
2963 770006 : 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 769997 : CPLErr eErr = CE_None;
2977 769997 : *pbStopProcessingOnCENone = FALSE;
2978 :
2979 769997 : if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2980 769995 : 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 769997 : 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 2334300 : for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2999 : {
3000 1564310 : int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
3001 1564310 : 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 1564310 : 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 769997 : 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 754441 : 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 754441 : if (psExtraArg == nullptr)
3158 : {
3159 554648 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3160 :
3161 : // 4 below inits are not strictly needed but make Coverity Scan
3162 : // happy
3163 554648 : sExtraArg.dfXOff = nXOff;
3164 554648 : sExtraArg.dfYOff = nYOff;
3165 554648 : sExtraArg.dfXSize = nXSize;
3166 554648 : sExtraArg.dfYSize = nYSize;
3167 :
3168 554648 : psExtraArg = &sExtraArg;
3169 : }
3170 199793 : 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 754441 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3179 : nBufYSize);
3180 :
3181 754441 : 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 754441 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3193 : {
3194 0 : ReportError(
3195 : CE_Failure, CPLE_IllegalArg,
3196 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3197 : eRWFlag);
3198 0 : return CE_Failure;
3199 : }
3200 :
3201 754441 : if (eRWFlag == GF_Write)
3202 : {
3203 216737 : if (CPL_UNLIKELY(eAccess != GA_Update))
3204 : {
3205 2 : ReportError(CE_Failure, CPLE_AppDefined,
3206 : "Write operation not permitted on dataset opened "
3207 : "in read-only mode");
3208 2 : return CE_Failure;
3209 : }
3210 : }
3211 :
3212 754439 : int bStopProcessing = FALSE;
3213 754439 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3214 : "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3215 : nBufYSize, nBandCount, panBandMap);
3216 754439 : if (eErr != CE_None || bStopProcessing)
3217 9 : return eErr;
3218 754430 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3219 : {
3220 2 : ReportError(CE_Failure, CPLE_AppDefined,
3221 : "Illegal GDT_Unknown/GDT_TypeCount argument");
3222 2 : return CE_Failure;
3223 : }
3224 :
3225 : /* -------------------------------------------------------------------- */
3226 : /* If pixel and line spacing are defaulted assign reasonable */
3227 : /* value assuming a packed buffer. */
3228 : /* -------------------------------------------------------------------- */
3229 754428 : if (nPixelSpace == 0)
3230 426590 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3231 :
3232 754428 : if (nLineSpace == 0)
3233 : {
3234 483905 : nLineSpace = nPixelSpace * nBufXSize;
3235 : }
3236 :
3237 754428 : if (nBandSpace == 0 && nBandCount > 1)
3238 : {
3239 68422 : nBandSpace = nLineSpace * nBufYSize;
3240 : }
3241 :
3242 754428 : if (panBandMap == nullptr)
3243 : {
3244 371324 : if (!m_poPrivate)
3245 0 : return CE_Failure;
3246 371324 : CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3247 371324 : panBandMap = m_poPrivate->m_anBandMap.data();
3248 : }
3249 :
3250 754428 : int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3251 :
3252 : /* -------------------------------------------------------------------- */
3253 : /* We are being forced to use cached IO instead of a driver */
3254 : /* specific implementation. */
3255 : /* -------------------------------------------------------------------- */
3256 754428 : if (bForceCachedIO)
3257 : {
3258 21 : eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3259 : nBufXSize, nBufYSize, eBufType, nBandCount,
3260 : panBandMap, nPixelSpace, nLineSpace,
3261 21 : nBandSpace, psExtraArg);
3262 : }
3263 :
3264 : /* -------------------------------------------------------------------- */
3265 : /* Call the format specific function. */
3266 : /* -------------------------------------------------------------------- */
3267 : else
3268 : {
3269 754407 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3270 : nBufXSize, nBufYSize, eBufType, nBandCount,
3271 : // TODO: remove this const_cast once IRasterIO()
3272 : // takes a const int*
3273 : const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3274 754407 : nBandSpace, psExtraArg);
3275 : }
3276 :
3277 754428 : if (bCallLeaveReadWrite)
3278 416290 : LeaveReadWrite();
3279 :
3280 754428 : return eErr;
3281 : }
3282 :
3283 : /************************************************************************/
3284 : /* GDALDatasetRasterIO() */
3285 : /************************************************************************/
3286 :
3287 : /**
3288 : * \brief Read/write a region of image data from multiple bands.
3289 : *
3290 : * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3291 : * resolution, progress callback, etc. are needed)
3292 : *
3293 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3294 : *
3295 : * @see GDALDataset::RasterIO()
3296 : */
3297 :
3298 4761 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3299 : int nXOff, int nYOff, int nXSize,
3300 : int nYSize, void *pData, int nBufXSize,
3301 : int nBufYSize, GDALDataType eBufType,
3302 : int nBandCount, const int *panBandMap,
3303 : int nPixelSpace, int nLineSpace,
3304 : int nBandSpace)
3305 :
3306 : {
3307 4761 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3308 :
3309 4761 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3310 :
3311 4761 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3312 : nBufXSize, nBufYSize, eBufType, nBandCount,
3313 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3314 4761 : nullptr);
3315 : }
3316 :
3317 : /************************************************************************/
3318 : /* GDALDatasetRasterIOEx() */
3319 : /************************************************************************/
3320 :
3321 : /**
3322 : * \brief Read/write a region of image data from multiple bands.
3323 : *
3324 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3325 : *
3326 : * @see GDALDataset::RasterIO()
3327 : */
3328 :
3329 353721 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3330 : GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3331 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
3332 : GDALDataType eBufType, int nBandCount, const int *panBandMap,
3333 : GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3334 : GDALRasterIOExtraArg *psExtraArg)
3335 :
3336 : {
3337 353721 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3338 :
3339 353721 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3340 :
3341 353721 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3342 : nBufXSize, nBufYSize, eBufType, nBandCount,
3343 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3344 353721 : psExtraArg);
3345 : }
3346 :
3347 : /************************************************************************/
3348 : /* GetOpenDatasets() */
3349 : /************************************************************************/
3350 :
3351 : /**
3352 : * \brief Fetch all open GDAL dataset handles.
3353 : *
3354 : * This method is the same as the C function GDALGetOpenDatasets().
3355 : *
3356 : * NOTE: This method is not thread safe. The returned list may change
3357 : * at any time and it should not be freed.
3358 : *
3359 : * @param pnCount integer into which to place the count of dataset pointers
3360 : * being returned.
3361 : *
3362 : * @return a pointer to an array of dataset handles.
3363 : */
3364 :
3365 2569 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3366 :
3367 : {
3368 5138 : CPLMutexHolderD(&hDLMutex);
3369 :
3370 2569 : if (poAllDatasetMap == nullptr)
3371 : {
3372 2548 : *pnCount = 0;
3373 2548 : return nullptr;
3374 : }
3375 :
3376 21 : *pnCount = static_cast<int>(poAllDatasetMap->size());
3377 21 : ppDatasets = static_cast<GDALDataset **>(
3378 21 : CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3379 21 : std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3380 600 : for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3381 579 : ppDatasets[i] = oIter->first;
3382 21 : return ppDatasets;
3383 : }
3384 :
3385 : /************************************************************************/
3386 : /* GDALGetOpenDatasets() */
3387 : /************************************************************************/
3388 :
3389 : /**
3390 : * \brief Fetch all open GDAL dataset handles.
3391 : *
3392 : * @see GDALDataset::GetOpenDatasets()
3393 : */
3394 :
3395 0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3396 :
3397 : {
3398 0 : VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3399 0 : VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3400 :
3401 0 : *ppahDSList =
3402 0 : reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3403 : }
3404 :
3405 : /************************************************************************/
3406 : /* GDALCleanOpenDatasetsList() */
3407 : /************************************************************************/
3408 :
3409 : // Useful when called from the child of a fork(), to avoid closing
3410 : // the datasets of the parent at the child termination.
3411 0 : void GDALNullifyOpenDatasetsList()
3412 : {
3413 0 : poAllDatasetMap = nullptr;
3414 0 : phSharedDatasetSet = nullptr;
3415 0 : ppDatasets = nullptr;
3416 0 : hDLMutex = nullptr;
3417 0 : }
3418 :
3419 : /************************************************************************/
3420 : /* GDALGetAccess() */
3421 : /************************************************************************/
3422 :
3423 : /**
3424 : * \brief Return access flag
3425 : *
3426 : * @see GDALDataset::GetAccess()
3427 : */
3428 :
3429 1 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3430 : {
3431 1 : VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3432 :
3433 1 : return GDALDataset::FromHandle(hDS)->GetAccess();
3434 : }
3435 :
3436 : /************************************************************************/
3437 : /* AdviseRead() */
3438 : /************************************************************************/
3439 :
3440 : /**
3441 : * \brief Advise driver of upcoming read requests.
3442 : *
3443 : * Some GDAL drivers operate more efficiently if they know in advance what
3444 : * set of upcoming read requests will be made. The AdviseRead() method allows
3445 : * an application to notify the driver of the region and bands of interest,
3446 : * and at what resolution the region will be read.
3447 : *
3448 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
3449 : * accelerate access via some drivers.
3450 : *
3451 : * Depending on call paths, drivers might receive several calls to
3452 : * AdviseRead() with the same parameters.
3453 : *
3454 : * @param nXOff The pixel offset to the top left corner of the region
3455 : * of the band to be accessed. This would be zero to start from the left side.
3456 : *
3457 : * @param nYOff The line offset to the top left corner of the region
3458 : * of the band to be accessed. This would be zero to start from the top.
3459 : *
3460 : * @param nXSize The width of the region of the band to be accessed in pixels.
3461 : *
3462 : * @param nYSize The height of the region of the band to be accessed in lines.
3463 : *
3464 : * @param nBufXSize the width of the buffer image into which the desired region
3465 : * is to be read, or from which it is to be written.
3466 : *
3467 : * @param nBufYSize the height of the buffer image into which the desired
3468 : * region is to be read, or from which it is to be written.
3469 : *
3470 : * @param eBufType the type of the pixel values in the pData data buffer. The
3471 : * pixel values will automatically be translated to/from the GDALRasterBand
3472 : * data type as needed.
3473 : *
3474 : * @param nBandCount the number of bands being read or written.
3475 : *
3476 : * @param panBandMap the list of nBandCount band numbers being read/written.
3477 : * Note band numbers are 1 based. This may be NULL to select the first
3478 : * nBandCount bands.
3479 : *
3480 : * @param papszOptions a list of name=value strings with special control
3481 : * options. Normally this is NULL.
3482 : *
3483 : * @return CE_Failure if the request is invalid and CE_None if it works or
3484 : * is ignored.
3485 : */
3486 :
3487 15411 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3488 : int nBufXSize, int nBufYSize,
3489 : GDALDataType eBufType, int nBandCount,
3490 : int *panBandMap, CSLConstList papszOptions)
3491 :
3492 : {
3493 : /* -------------------------------------------------------------------- */
3494 : /* Do some validation of parameters. */
3495 : /* -------------------------------------------------------------------- */
3496 15411 : int bStopProcessing = FALSE;
3497 15411 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3498 : "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3499 : nBufXSize, nBufYSize, nBandCount, panBandMap);
3500 15411 : if (eErr != CE_None || bStopProcessing)
3501 143 : return eErr;
3502 :
3503 130264 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3504 : {
3505 115000 : GDALRasterBand *poBand = nullptr;
3506 :
3507 115000 : if (panBandMap == nullptr)
3508 113480 : poBand = GetRasterBand(iBand + 1);
3509 : else
3510 1520 : poBand = GetRasterBand(panBandMap[iBand]);
3511 :
3512 115000 : if (poBand == nullptr)
3513 0 : return CE_Failure;
3514 :
3515 230000 : eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3516 115000 : nBufYSize, eBufType, papszOptions);
3517 :
3518 115000 : if (eErr != CE_None)
3519 4 : return eErr;
3520 : }
3521 :
3522 15264 : return CE_None;
3523 : }
3524 :
3525 : /************************************************************************/
3526 : /* GDALDatasetAdviseRead() */
3527 : /************************************************************************/
3528 :
3529 : /**
3530 : * \brief Advise driver of upcoming read requests.
3531 : *
3532 : * @see GDALDataset::AdviseRead()
3533 : */
3534 7 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3535 : int nXSize, int nYSize, int nBufXSize,
3536 : int nBufYSize, GDALDataType eDT,
3537 : int nBandCount, int *panBandMap,
3538 : CSLConstList papszOptions)
3539 :
3540 : {
3541 7 : VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3542 :
3543 14 : return GDALDataset::FromHandle(hDS)->AdviseRead(
3544 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3545 7 : panBandMap, const_cast<char **>(papszOptions));
3546 : }
3547 :
3548 : /************************************************************************/
3549 : /* GDALAntiRecursionStruct */
3550 : /************************************************************************/
3551 :
3552 : // Prevent infinite recursion.
3553 : struct GDALAntiRecursionStruct
3554 : {
3555 : struct DatasetContext
3556 : {
3557 : std::string osFilename;
3558 : int nOpenFlags;
3559 : std::string osAllowedDrivers;
3560 :
3561 88177 : DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3562 : const std::string &osAllowedDriversIn)
3563 88177 : : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3564 88177 : osAllowedDrivers(osAllowedDriversIn)
3565 : {
3566 88177 : }
3567 : };
3568 :
3569 : struct DatasetContextCompare
3570 : {
3571 1105280 : bool operator()(const DatasetContext &lhs,
3572 : const DatasetContext &rhs) const
3573 : {
3574 3237980 : return lhs.osFilename < rhs.osFilename ||
3575 1073370 : (lhs.osFilename == rhs.osFilename &&
3576 1059330 : (lhs.nOpenFlags < rhs.nOpenFlags ||
3577 2102300 : (lhs.nOpenFlags == rhs.nOpenFlags &&
3578 2154380 : lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3579 : }
3580 : };
3581 :
3582 1415 : ~GDALAntiRecursionStruct()
3583 1415 : {
3584 1415 : CPLAssert(aosDatasetNamesWithFlags.empty());
3585 1415 : CPLAssert(nRecLevel == 0);
3586 1415 : CPLAssert(m_oMapDepth.empty());
3587 1415 : }
3588 :
3589 : std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3590 : int nRecLevel = 0;
3591 : std::map<std::string, int> m_oMapDepth{};
3592 : };
3593 :
3594 : #ifdef _WIN32
3595 : // Currently thread_local and C++ objects don't work well with DLL on Windows
3596 : static void FreeAntiRecursionOpen(void *pData)
3597 : {
3598 : delete static_cast<GDALAntiRecursionStruct *>(pData);
3599 : }
3600 :
3601 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3602 : {
3603 : static GDALAntiRecursionStruct dummy;
3604 : int bMemoryErrorOccurred = false;
3605 : void *pData =
3606 : CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3607 : if (bMemoryErrorOccurred)
3608 : {
3609 : return dummy;
3610 : }
3611 : if (pData == nullptr)
3612 : {
3613 : auto pAntiRecursion = new GDALAntiRecursionStruct();
3614 : CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3615 : FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3616 : if (bMemoryErrorOccurred)
3617 : {
3618 : delete pAntiRecursion;
3619 : return dummy;
3620 : }
3621 : return *pAntiRecursion;
3622 : }
3623 : return *static_cast<GDALAntiRecursionStruct *>(pData);
3624 : }
3625 : #else
3626 : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3627 :
3628 388129 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3629 : {
3630 388129 : return g_tls_antiRecursion;
3631 : }
3632 : #endif
3633 :
3634 : //! @cond Doxygen_Suppress
3635 299952 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3636 299952 : : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3637 : m_osIdentifier(osIdentifier),
3638 299952 : m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3639 : {
3640 299952 : CPLAssert(!osIdentifier.empty());
3641 299952 : }
3642 :
3643 299952 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3644 299952 : const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3645 299952 : : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3646 299952 : m_osIdentifier(osIdentifier.empty()
3647 : ? osIdentifier
3648 31147 : : other.m_osIdentifier + osIdentifier),
3649 299952 : m_nDepth(m_osIdentifier.empty()
3650 299952 : ? 0
3651 331099 : : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3652 : {
3653 299952 : }
3654 :
3655 599904 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3656 : {
3657 599904 : if (!m_osIdentifier.empty())
3658 : {
3659 331099 : auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3660 331099 : CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3661 331099 : if (--(oIter->second) == 0)
3662 326643 : m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3663 : }
3664 599904 : }
3665 :
3666 : //! @endcond
3667 :
3668 : /************************************************************************/
3669 : /* GetFileList() */
3670 : /************************************************************************/
3671 :
3672 : /**
3673 : * \brief Fetch files forming dataset.
3674 : *
3675 : * Returns a list of files believed to be part of this dataset. If it returns
3676 : * an empty list of files it means there is believed to be no local file
3677 : * system files associated with the dataset (for instance a virtual dataset).
3678 : * The returned file list is owned by the caller and should be deallocated
3679 : * with CSLDestroy().
3680 : *
3681 : * The returned filenames will normally be relative or absolute paths
3682 : * depending on the path used to originally open the dataset. The strings
3683 : * will be UTF-8 encoded.
3684 : *
3685 : * This method is the same as the C GDALGetFileList() function.
3686 : *
3687 : * @return NULL or a NULL terminated array of file names.
3688 : */
3689 :
3690 4759 : char **GDALDataset::GetFileList()
3691 :
3692 : {
3693 9518 : CPLString osMainFilename = GetDescription();
3694 : VSIStatBufL sStat;
3695 :
3696 4759 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3697 : GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3698 9518 : std::string());
3699 4759 : auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3700 4759 : if (cpl::contains(aosDatasetList, datasetCtxt))
3701 0 : return nullptr;
3702 :
3703 : /* -------------------------------------------------------------------- */
3704 : /* Is the main filename even a real filesystem object? */
3705 : /* -------------------------------------------------------------------- */
3706 : int bMainFileReal =
3707 4759 : VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3708 :
3709 : /* -------------------------------------------------------------------- */
3710 : /* Form new list. */
3711 : /* -------------------------------------------------------------------- */
3712 4759 : char **papszList = nullptr;
3713 :
3714 4759 : if (bMainFileReal)
3715 4679 : papszList = CSLAddString(papszList, osMainFilename);
3716 :
3717 4759 : if (sAntiRecursion.nRecLevel == 100)
3718 : {
3719 0 : CPLError(CE_Failure, CPLE_AppDefined,
3720 : "GetFileList() called with too many recursion levels");
3721 0 : return papszList;
3722 : }
3723 4759 : ++sAntiRecursion.nRecLevel;
3724 :
3725 : /* -------------------------------------------------------------------- */
3726 : /* Do we have a known overview file? */
3727 : /* -------------------------------------------------------------------- */
3728 4759 : if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3729 : {
3730 60 : auto iter = aosDatasetList.insert(datasetCtxt).first;
3731 60 : char **papszOvrList = oOvManager.poODS->GetFileList();
3732 60 : papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3733 60 : CSLDestroy(papszOvrList);
3734 60 : aosDatasetList.erase(iter);
3735 : }
3736 :
3737 : /* -------------------------------------------------------------------- */
3738 : /* Do we have a known mask file? */
3739 : /* -------------------------------------------------------------------- */
3740 4759 : if (oOvManager.HaveMaskFile())
3741 : {
3742 9 : auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3743 9 : for (const char *pszFile :
3744 18 : CPLStringList(oOvManager.poMaskDS->GetFileList()))
3745 : {
3746 9 : if (CSLFindString(papszList, pszFile) < 0)
3747 9 : papszList = CSLAddString(papszList, pszFile);
3748 : }
3749 9 : aosDatasetList.erase(iter);
3750 : }
3751 :
3752 4759 : --sAntiRecursion.nRecLevel;
3753 :
3754 4759 : return papszList;
3755 : }
3756 :
3757 : /************************************************************************/
3758 : /* GDALGetFileList() */
3759 : /************************************************************************/
3760 :
3761 : /**
3762 : * \brief Fetch files forming dataset.
3763 : *
3764 : * @see GDALDataset::GetFileList()
3765 : */
3766 :
3767 3731 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3768 :
3769 : {
3770 3731 : VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3771 :
3772 3731 : return GDALDataset::FromHandle(hDS)->GetFileList();
3773 : }
3774 :
3775 : /************************************************************************/
3776 : /* CreateMaskBand() */
3777 : /************************************************************************/
3778 :
3779 : /**
3780 : * \brief Adds a mask band to the dataset
3781 : *
3782 : * The default implementation of the CreateMaskBand() method is implemented
3783 : * based on similar rules to the .ovr handling implemented using the
3784 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3785 : * be created with the same basename as the original file, and it will have
3786 : * one band.
3787 : * The mask images will be deflate compressed tiled images with the same
3788 : * block size as the original image if possible.
3789 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3790 : * level, where xx matches the band number of a band of the main dataset. The
3791 : * value of those items will be the one of the nFlagsIn parameter.
3792 : *
3793 : * Note that if you got a mask band with a previous call to GetMaskBand(), it
3794 : * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3795 : * again.
3796 : *
3797 : *
3798 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3799 : * GMF_PER_DATASET will be always set, even if not explicitly
3800 : * specified.
3801 : * @return CE_None on success or CE_Failure on an error.
3802 : *
3803 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3804 : * @see GDALRasterBand::CreateMaskBand()
3805 : *
3806 : */
3807 17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3808 :
3809 : {
3810 17 : if (oOvManager.IsInitialized())
3811 : {
3812 17 : CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3813 17 : if (eErr != CE_None)
3814 0 : return eErr;
3815 :
3816 : // Invalidate existing raster band masks.
3817 45 : for (int i = 0; i < nBands; ++i)
3818 : {
3819 28 : GDALRasterBand *poBand = papoBands[i];
3820 28 : poBand->poMask.reset();
3821 : }
3822 :
3823 17 : return CE_None;
3824 : }
3825 :
3826 0 : ReportError(CE_Failure, CPLE_NotSupported,
3827 : "CreateMaskBand() not supported for this dataset.");
3828 :
3829 0 : return CE_Failure;
3830 : }
3831 :
3832 : /************************************************************************/
3833 : /* GDALCreateDatasetMaskBand() */
3834 : /************************************************************************/
3835 :
3836 : /**
3837 : * \brief Adds a mask band to the dataset
3838 : * @see GDALDataset::CreateMaskBand()
3839 : */
3840 109 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3841 :
3842 : {
3843 109 : VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3844 :
3845 109 : return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3846 : }
3847 :
3848 : /************************************************************************/
3849 : /* GDALOpen() */
3850 : /************************************************************************/
3851 :
3852 : /**
3853 : * \brief Open a raster file as a GDALDataset.
3854 : *
3855 : * This function will try to open the passed file, or virtual dataset
3856 : * name by invoking the Open method of each registered GDALDriver in turn.
3857 : * The first successful open will result in a returned dataset. If all
3858 : * drivers fail then NULL is returned and an error is issued.
3859 : *
3860 : * Several recommendations :
3861 : * <ul>
3862 : * <li>If you open a dataset object with GA_Update access, it is not recommended
3863 : * to open a new dataset on the same underlying file.</li>
3864 : * <li>The returned dataset should only be accessed by one thread at a time. If
3865 : * you want to use it from different threads, you must add all necessary code
3866 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3867 : * as GeoTIFF, maintain internal state variables that are updated each time a
3868 : * new block is read, thus preventing concurrent use.) </li>
3869 : * </ul>
3870 : *
3871 : * For drivers supporting the VSI virtual file API, it is possible to open a
3872 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3873 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3874 : * server (see VSIInstallCurlFileHandler())
3875 : *
3876 : * \sa GDALOpenShared()
3877 : * \sa GDALOpenEx()
3878 : *
3879 : * @param pszFilename the name of the file to access. In the case of
3880 : * exotic drivers this may not refer to a physical file, but instead contain
3881 : * information for the driver on how to access a dataset. It should be in UTF-8
3882 : * encoding.
3883 : *
3884 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
3885 : * drivers support only read only access.
3886 : *
3887 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
3888 : * this handle can be cast to a GDALDataset *.
3889 : */
3890 :
3891 25587 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3892 :
3893 : {
3894 25587 : const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3895 25587 : const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3896 : GDALDatasetH hDataset =
3897 25587 : GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3898 25587 : return hDataset;
3899 : }
3900 :
3901 : /************************************************************************/
3902 : /* GetSharedDS() */
3903 : /************************************************************************/
3904 :
3905 6491 : static GDALDataset *GetSharedDS(const char *pszFilename,
3906 : unsigned int nOpenFlags,
3907 : const char *const *papszOpenOptions)
3908 : {
3909 12982 : CPLMutexHolderD(&hDLMutex);
3910 :
3911 6491 : if (phSharedDatasetSet != nullptr)
3912 : {
3913 6240 : const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3914 : SharedDatasetCtxt sStruct;
3915 :
3916 6240 : sStruct.nPID = nThisPID;
3917 6240 : sStruct.pszDescription = const_cast<char *>(pszFilename);
3918 6240 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3919 : std::string osConcatenatedOpenOptions =
3920 6240 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3921 6240 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3922 6240 : sStruct.poDS = nullptr;
3923 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3924 6240 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3925 6240 : if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3926 : {
3927 135 : sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3928 : psStruct = static_cast<SharedDatasetCtxt *>(
3929 135 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3930 : }
3931 6240 : if (psStruct)
3932 : {
3933 6106 : return psStruct->poDS;
3934 : }
3935 : }
3936 385 : return nullptr;
3937 : }
3938 :
3939 : /************************************************************************/
3940 : /* GDALOpenEx() */
3941 : /************************************************************************/
3942 :
3943 : /**
3944 : * \brief Open a raster or vector file as a GDALDataset.
3945 : *
3946 : * This function will try to open the passed file, or virtual dataset
3947 : * name by invoking the Open method of each registered GDALDriver in turn.
3948 : * The first successful open will result in a returned dataset. If all
3949 : * drivers fail then NULL is returned and an error is issued.
3950 : *
3951 : * Several recommendations :
3952 : * <ul>
3953 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3954 : * recommended to open a new dataset on the same underlying file.</li>
3955 : * <li>The returned dataset should only be accessed by one thread at a time. If
3956 : * you want to use it from different threads, you must add all necessary code
3957 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3958 : * as GeoTIFF, maintain internal state variables that are updated each time a
3959 : * new block is read, thus preventing concurrent use.) </li>
3960 : * </ul>
3961 : *
3962 : * For drivers supporting the VSI virtual file API, it is possible to open a
3963 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3964 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3965 : * server (see VSIInstallCurlFileHandler())
3966 : *
3967 : * In order to reduce the need for searches through the operating system
3968 : * file system machinery, it is possible to give an optional list of files with
3969 : * the papszSiblingFiles parameter.
3970 : * This is the list of all files at the same level in the file system as the
3971 : * target file, including the target file. The filenames must not include any
3972 : * path components, are essentially just the output of VSIReadDir() on the
3973 : * parent directory. If the target object does not have filesystem semantics
3974 : * then the file list should be NULL.
3975 : *
3976 : * @param pszFilename the name of the file to access. In the case of
3977 : * exotic drivers this may not refer to a physical file, but instead contain
3978 : * information for the driver on how to access a dataset. It should be in UTF-8
3979 : * encoding.
3980 : *
3981 : * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3982 : * through logical or operator.
3983 : * <ul>
3984 : * <li>Driver kind:
3985 : * <ul>
3986 : * <li>GDAL_OF_RASTER for raster drivers,</li>
3987 : * <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3988 : * <li>GDAL_OF_VECTOR for vector drivers,</li>
3989 : * <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3990 : * </ul>
3991 : * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3992 : * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3993 : * | GDAL_OF_GNM is implied.
3994 : * </li>
3995 : * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3996 : * </li>
3997 : * <li>Shared mode: GDAL_OF_SHARED. If set,
3998 : * it allows the sharing of GDALDataset handles for a dataset with other callers
3999 : * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
4000 : * its list of currently open and shared GDALDataset's, and if the
4001 : * GetDescription() name for one exactly matches the pszFilename passed to
4002 : * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
4003 : * from the same thread.
4004 : * </li>
4005 : * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
4006 : * This must be use in combination with GDAL_OF_RASTER, and is mutually
4007 : * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4008 : * GDAL_OF_GNM.
4009 : * </li>
4010 : * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4011 : * a failed attempt to open the file will lead to an error message to be
4012 : * reported.
4013 : * </li>
4014 : * </ul>
4015 : *
4016 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4017 : * terminated list of strings with the driver short names that must be
4018 : * considered.
4019 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4020 : * followed by the driver short name can be used to exclude a driver.
4021 : *
4022 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4023 : * options passed to candidate drivers. An option exists for all drivers,
4024 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4025 : * The level index starts at 0. The level number can be suffixed by "only" to
4026 : * specify that only this overview level must be visible, and not sub-levels.
4027 : * Open options are validated by default, and a warning is emitted in case the
4028 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4029 : * when not knowing which driver will open the file), so the special open option
4030 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4031 : * that it may not cause a warning if the driver doesn't declare this option.
4032 : * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4033 : * no overviews should be exposed.
4034 : *
4035 : * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4036 : * filenames that are auxiliary to the main filename. If NULL is passed, a
4037 : * probing of the file system will be done.
4038 : *
4039 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4040 : * this handle can be cast to a GDALDataset *.
4041 : *
4042 : */
4043 :
4044 87533 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4045 : unsigned int nOpenFlags,
4046 : const char *const *papszAllowedDrivers,
4047 : const char *const *papszOpenOptions,
4048 : const char *const *papszSiblingFiles)
4049 : {
4050 87533 : VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4051 :
4052 : // Do some sanity checks on incompatible flags with thread-safe mode.
4053 87533 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4054 : {
4055 : const struct
4056 : {
4057 : int nFlag;
4058 : const char *pszFlagName;
4059 128 : } asFlags[] = {
4060 : {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4061 : {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4062 : {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4063 : {GDAL_OF_GNM, "GDAL_OF_GNM"},
4064 : };
4065 :
4066 630 : for (const auto &asFlag : asFlags)
4067 : {
4068 506 : if ((nOpenFlags & asFlag.nFlag) != 0)
4069 : {
4070 4 : CPLError(CE_Failure, CPLE_IllegalArg,
4071 : "GDAL_OF_THREAD_SAFE and %s are mutually "
4072 : "exclusive",
4073 4 : asFlag.pszFlagName);
4074 4 : return nullptr;
4075 : }
4076 : }
4077 : }
4078 :
4079 : // If no driver kind is specified, assume all are to be probed.
4080 87529 : if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4081 9376 : nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4082 :
4083 : /* -------------------------------------------------------------------- */
4084 : /* In case of shared dataset, first scan the existing list to see */
4085 : /* if it could already contain the requested dataset. */
4086 : /* -------------------------------------------------------------------- */
4087 87529 : if (nOpenFlags & GDAL_OF_SHARED)
4088 : {
4089 6491 : if (nOpenFlags & GDAL_OF_INTERNAL)
4090 : {
4091 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4092 : "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4093 0 : return nullptr;
4094 : }
4095 :
4096 : auto poSharedDS =
4097 6491 : GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4098 6491 : if (poSharedDS)
4099 : {
4100 6106 : poSharedDS->Reference();
4101 6106 : return poSharedDS;
4102 : }
4103 : }
4104 :
4105 81423 : CPLErrorReset();
4106 81423 : VSIErrorReset();
4107 :
4108 : // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4109 : // shared dataset was asked before.
4110 81423 : GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4111 :
4112 162846 : return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4113 81423 : .release();
4114 : }
4115 :
4116 : /************************************************************************/
4117 : /* GDALDataset::Open() */
4118 : /************************************************************************/
4119 :
4120 : /**
4121 : * \brief Open a raster or vector file as a GDALDataset.
4122 : *
4123 : * This function will use the passed open info on each registered GDALDriver in
4124 : * turn.
4125 : * The first successful open will result in a returned dataset. If all
4126 : * drivers fail then NULL is returned and an error is issued.
4127 : *
4128 : * Several recommendations :
4129 : * <ul>
4130 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4131 : * recommended to open a new dataset on the same underlying file.</li>
4132 : * <li>The returned dataset should only be accessed by one thread at a time. If
4133 : * you want to use it from different threads, you must add all necessary code
4134 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
4135 : * as GeoTIFF, maintain internal state variables that are updated each time a
4136 : * new block is read, thus preventing concurrent use.) </li>
4137 : * </ul>
4138 : *
4139 : * For drivers supporting the VSI virtual file API, it is possible to open a
4140 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4141 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4142 : * server (see VSIInstallCurlFileHandler())
4143 : *
4144 : * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4145 : * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4146 : * If shared dataset is needed, use GDALOpenEx() or the other variant of
4147 : * GDALDataset::Open()
4148 : *
4149 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4150 : * terminated list of strings with the driver short names that must be
4151 : * considered.
4152 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4153 : * followed by the driver short name can be used to exclude a driver.
4154 : *
4155 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4156 : * options passed to candidate drivers. An option exists for all drivers,
4157 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4158 : * The level index starts at 0. The level number can be suffixed by "only" to
4159 : * specify that only this overview level must be visible, and not sub-levels.
4160 : * Open options are validated by default, and a warning is emitted in case the
4161 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4162 : * when not knowing which driver will open the file), so the special open option
4163 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4164 : * that it may not cause a warning if the driver doesn't declare this option.
4165 : * OVERVIEW_LEVEL=NONE is supported to indicate that
4166 : * no overviews should be exposed.
4167 : *
4168 : * @return A GDALDataset unique pointer or NULL on failure.
4169 : *
4170 : * @since 3.13
4171 : */
4172 :
4173 : std::unique_ptr<GDALDataset>
4174 83418 : GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4175 : const char *const *papszAllowedDrivers,
4176 : const char *const *papszOpenOptions)
4177 : {
4178 : // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4179 : // into VSIKERCHUNK_USE_CACHE config option
4180 83418 : std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4181 83418 : if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4182 : {
4183 13 : poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4184 26 : "VSIKERCHUNK_USE_CACHE", "YES", false);
4185 : }
4186 :
4187 83418 : GDALDriverManager *poDM = GetGDALDriverManager();
4188 :
4189 83418 : CPLAssert(nullptr != poDM);
4190 :
4191 83418 : GDALOpenInfo &oOpenInfo = *poOpenInfo;
4192 83418 : const char *pszFilename = poOpenInfo->pszFilename;
4193 83418 : const int nOpenFlags = poOpenInfo->nOpenFlags;
4194 83418 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4195 :
4196 83418 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4197 83418 : if (sAntiRecursion.nRecLevel == 100)
4198 : {
4199 0 : CPLError(CE_Failure, CPLE_AppDefined,
4200 : "GDALOpen() called with too many recursion levels");
4201 0 : return nullptr;
4202 : }
4203 :
4204 166836 : std::string osAllowedDrivers;
4205 178929 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4206 95511 : osAllowedDrivers += pszDriverName;
4207 : auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4208 250254 : std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4209 83418 : if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4210 : {
4211 0 : CPLError(CE_Failure, CPLE_AppDefined,
4212 : "GDALOpen() called on %s recursively", pszFilename);
4213 0 : return nullptr;
4214 : }
4215 :
4216 : // Remove leading @ if present.
4217 : char **papszOpenOptionsCleaned =
4218 83418 : CSLDuplicate(const_cast<char **>(papszOpenOptions));
4219 89338 : for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4220 : ++papszIter)
4221 : {
4222 5920 : char *pszOption = *papszIter;
4223 5920 : if (pszOption[0] == '@')
4224 230 : memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4225 : }
4226 :
4227 83418 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4228 83418 : oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4229 :
4230 : #ifdef OGRAPISPY_ENABLED
4231 83418 : const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4232 : const int iSnapshot =
4233 21922 : (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4234 105340 : ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4235 83418 : : INT_MIN;
4236 : #endif
4237 :
4238 83418 : const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4239 83418 : GDALDriver *poMissingPluginDriver = nullptr;
4240 166836 : std::vector<GDALDriver *> apoSecondPassDrivers;
4241 :
4242 : // Lookup of matching driver for dataset can involve up to 2 passes:
4243 : // - in the first pass, all drivers that are compabile of the request mode
4244 : // (raster/vector/etc.) are probed using their Identify() method if it
4245 : // exists. If the Identify() method returns FALSE, the driver is skipped.
4246 : // If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4247 : // driver is a deferred-loading plugin, it is added to the
4248 : // apoSecondPassDrivers list for potential later probing, and execution
4249 : // continues to the next driver in the list.
4250 : // Otherwise if Identify() returns non-FALSE, the Open() method is used.
4251 : // If Open() returns a non-NULL dataset, the loop stops and it is
4252 : // returned. Otherwise looping over remaining drivers continues.
4253 : // - the second pass is optional, only if at least one driver was added
4254 : // into apoSecondPassDrivers during the first pass. It is similar
4255 : // to the first pass except it runs only on apoSecondPassDrivers drivers.
4256 : // And the Open() method of such drivers is used, causing them to be
4257 : // loaded for real.
4258 83418 : int iPass = 1;
4259 83432 : retry:
4260 8772180 : for (int iDriver = 0;
4261 8772210 : iDriver < (iPass == 1 ? nDriverCount
4262 34 : : static_cast<int>(apoSecondPassDrivers.size()));
4263 : ++iDriver)
4264 : {
4265 : GDALDriver *poDriver =
4266 8753160 : iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4267 25 : : apoSecondPassDrivers[iDriver];
4268 8753140 : const char *pszDriverName = GDALGetDriverShortName(poDriver);
4269 8753140 : if (pszDriverName && papszAllowedDrivers)
4270 : {
4271 3809590 : bool bDriverMatchedPositively = false;
4272 3809590 : bool bDriverMatchedNegatively = false;
4273 3809590 : bool bOnlyExcludedDrivers = true;
4274 18392000 : for (const char *pszAllowedDriver :
4275 40593600 : cpl::Iterate(papszAllowedDrivers))
4276 : {
4277 18392000 : if (pszAllowedDriver[0] != '-')
4278 18390500 : bOnlyExcludedDrivers = false;
4279 18392000 : if (EQUAL(pszAllowedDriver, pszDriverName))
4280 : {
4281 90322 : bDriverMatchedPositively = true;
4282 : }
4283 18301700 : else if (pszAllowedDriver[0] == '-' &&
4284 1474 : EQUAL(pszAllowedDriver + 1, pszDriverName))
4285 : {
4286 7 : bDriverMatchedNegatively = true;
4287 7 : break;
4288 : }
4289 : }
4290 3809590 : if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4291 : bDriverMatchedNegatively)
4292 : {
4293 8228690 : continue;
4294 : }
4295 : }
4296 :
4297 5037160 : if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4298 47530 : continue;
4299 :
4300 13172500 : if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4301 7168520 : (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4302 2178890 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4303 502052 : continue;
4304 12922700 : if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4305 6450460 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4306 1962880 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4307 1472400 : continue;
4308 6690010 : if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4309 3349750 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4310 334570 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4311 314170 : continue;
4312 :
4313 : // Remove general OVERVIEW_LEVEL open options from list before passing
4314 : // it to the driver, if it isn't a driver specific option already.
4315 2701010 : char **papszTmpOpenOptions = nullptr;
4316 2701010 : char **papszTmpOpenOptionsToValidate = nullptr;
4317 2701010 : char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4318 2701010 : if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4319 2701160 : nullptr &&
4320 152 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4321 : {
4322 152 : papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4323 : papszTmpOpenOptions =
4324 152 : CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4325 152 : oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4326 :
4327 152 : papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4328 152 : papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4329 : "OVERVIEW_LEVEL", nullptr);
4330 152 : papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4331 : }
4332 :
4333 : const int nIdentifyRes =
4334 2701010 : poDriver->pfnIdentifyEx
4335 5402000 : ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4336 2701000 : : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4337 2701010 : : GDAL_IDENTIFY_UNKNOWN;
4338 2701010 : if (nIdentifyRes == FALSE)
4339 : {
4340 2176460 : CSLDestroy(papszTmpOpenOptions);
4341 2176460 : CSLDestroy(papszTmpOpenOptionsToValidate);
4342 2176460 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4343 2176460 : continue;
4344 : }
4345 524523 : else if (iPass == 1 && nIdentifyRes < 0 &&
4346 1049170 : poDriver->pfnOpen == nullptr &&
4347 100 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4348 : {
4349 : // Not loaded plugin
4350 97 : apoSecondPassDrivers.push_back(poDriver);
4351 97 : CSLDestroy(papszTmpOpenOptions);
4352 97 : CSLDestroy(papszTmpOpenOptionsToValidate);
4353 97 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4354 97 : continue;
4355 : }
4356 :
4357 524451 : const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4358 524451 : if (bIdentifyRes)
4359 : {
4360 63368 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4361 : }
4362 :
4363 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4364 : const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4365 : CPLErrorReset();
4366 : #endif
4367 :
4368 524451 : sAntiRecursion.nRecLevel++;
4369 524451 : sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4370 :
4371 524451 : GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4372 :
4373 524451 : sAntiRecursion.nRecLevel--;
4374 524451 : sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4375 :
4376 524451 : if (poDriver->pfnOpen != nullptr)
4377 : {
4378 : // If we couldn't determine for sure with Identify() (it returned
4379 : // -1), but Open() managed to open the file, post validate options.
4380 524448 : if (poDS != nullptr &&
4381 63112 : (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4382 62544 : !bIdentifyRes)
4383 : {
4384 895 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4385 : }
4386 : }
4387 3 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
4388 : {
4389 : // do nothing
4390 : }
4391 0 : else if (bIdentifyRes &&
4392 0 : poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4393 : {
4394 0 : if (!poMissingPluginDriver)
4395 : {
4396 0 : poMissingPluginDriver = poDriver;
4397 : }
4398 : }
4399 : else
4400 : {
4401 : // should not happen given the GDAL_DCAP_OPEN check
4402 0 : CSLDestroy(papszTmpOpenOptions);
4403 0 : CSLDestroy(papszTmpOpenOptionsToValidate);
4404 0 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4405 0 : continue;
4406 : }
4407 :
4408 524451 : CSLDestroy(papszTmpOpenOptions);
4409 524451 : CSLDestroy(papszTmpOpenOptionsToValidate);
4410 524451 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4411 :
4412 524451 : if (poDS != nullptr)
4413 : {
4414 63115 : if (poDS->papszOpenOptions == nullptr)
4415 : {
4416 62845 : poDS->papszOpenOptions = papszOpenOptionsCleaned;
4417 62845 : papszOpenOptionsCleaned = nullptr;
4418 : }
4419 :
4420 : // Deal with generic OVERVIEW_LEVEL open option, unless it is
4421 : // driver specific.
4422 63115 : if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4423 63154 : nullptr &&
4424 39 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4425 : {
4426 : CPLString osVal(
4427 78 : CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4428 39 : const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4429 : const bool bThisLevelOnly =
4430 39 : nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4431 : GDALDataset *poOvrDS =
4432 39 : GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4433 39 : if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4434 : {
4435 4 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4436 : {
4437 0 : CPLError(
4438 : CE_Warning, CPLE_NotSupported,
4439 : "A dataset opened by GDALOpenShared should have "
4440 : "the same filename (%s) "
4441 : "and description (%s)",
4442 0 : pszFilename, poDS->GetDescription());
4443 : }
4444 : else
4445 : {
4446 4 : CSLDestroy(poDS->papszOpenOptions);
4447 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4448 4 : poDS->papszOpenOptions = CSLSetNameValue(
4449 : poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4450 : }
4451 : }
4452 39 : poDS->ReleaseRef();
4453 39 : poDS = poOvrDS;
4454 39 : if (poDS == nullptr)
4455 : {
4456 1 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4457 : {
4458 1 : CPLError(CE_Failure, CPLE_OpenFailed,
4459 : "Cannot open overview level %d of %s",
4460 : nOvrLevel, pszFilename);
4461 : }
4462 : }
4463 : else
4464 : {
4465 : // For thread-safe opening, currently poDS is what will be
4466 : // the "master" dataset owned by the thread-safe dataset
4467 : // returned to the user, hence we do not register it as a
4468 : // visible one in the open dataset list, or mark it as shared.
4469 38 : if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4470 36 : !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4471 : {
4472 35 : poDS->AddToDatasetOpenList();
4473 : }
4474 38 : if (nOpenFlags & GDAL_OF_SHARED)
4475 : {
4476 4 : CSLDestroy(poDS->papszOpenOptions);
4477 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4478 4 : poDS->nOpenFlags = nOpenFlags;
4479 4 : if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4480 4 : poDS->MarkAsShared();
4481 : }
4482 : }
4483 : }
4484 63076 : else if (nOpenFlags & GDAL_OF_SHARED)
4485 : {
4486 375 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4487 : {
4488 2 : CPLError(CE_Warning, CPLE_NotSupported,
4489 : "A dataset opened by GDALOpenShared should have "
4490 : "the same filename (%s) "
4491 : "and description (%s)",
4492 2 : pszFilename, poDS->GetDescription());
4493 : }
4494 373 : else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4495 : {
4496 : // For thread-safe opening, currently poDS is what will be
4497 : // the "master" dataset owned by the thread-safe dataset
4498 : // returned to the user, hence we do not or mark it as shared.
4499 373 : poDS->MarkAsShared();
4500 : }
4501 : }
4502 :
4503 63115 : VSIErrorReset();
4504 :
4505 63115 : CSLDestroy(papszOpenOptionsCleaned);
4506 :
4507 : #ifdef OGRAPISPY_ENABLED
4508 63115 : if (iSnapshot != INT_MIN)
4509 : {
4510 11987 : GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4511 11987 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4512 11987 : poDS = GDALDataset::FromHandle(hDS);
4513 : }
4514 : #endif
4515 :
4516 63115 : if (poDS)
4517 : {
4518 63114 : poDS->m_bCanBeReopened = true;
4519 :
4520 63114 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4521 : {
4522 : poDS =
4523 248 : GDALGetThreadSafeDataset(
4524 248 : std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4525 124 : .release();
4526 124 : if (poDS)
4527 : {
4528 124 : poDS->m_bCanBeReopened = true;
4529 124 : poDS->poDriver = poDriver;
4530 124 : poDS->nOpenFlags = nOpenFlags;
4531 124 : if (!(nOpenFlags & GDAL_OF_INTERNAL))
4532 124 : poDS->AddToDatasetOpenList();
4533 124 : if (nOpenFlags & GDAL_OF_SHARED)
4534 0 : poDS->MarkAsShared();
4535 : }
4536 : }
4537 : }
4538 :
4539 64392 : return std::unique_ptr<GDALDataset>(poDS);
4540 : }
4541 :
4542 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4543 : if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4544 : {
4545 : // In case the file descriptor was "consumed" by a driver
4546 : // that ultimately failed, re-open it for next drivers.
4547 : oOpenInfo.fpL = VSIFOpenL(
4548 : pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4549 : }
4550 : #else
4551 461336 : if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4552 : {
4553 1277 : CSLDestroy(papszOpenOptionsCleaned);
4554 :
4555 : #ifdef OGRAPISPY_ENABLED
4556 1277 : if (iSnapshot != INT_MIN)
4557 : {
4558 349 : GDALDatasetH hDS = nullptr;
4559 349 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4560 : }
4561 : #endif
4562 1277 : return nullptr;
4563 : }
4564 : #endif
4565 : }
4566 :
4567 : // cppcheck-suppress knownConditionTrueFalse
4568 19040 : if (iPass == 1 && !apoSecondPassDrivers.empty())
4569 : {
4570 14 : CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4571 14 : iPass = 2;
4572 14 : goto retry;
4573 : }
4574 :
4575 19026 : CSLDestroy(papszOpenOptionsCleaned);
4576 :
4577 : #ifdef OGRAPISPY_ENABLED
4578 19026 : if (iSnapshot != INT_MIN)
4579 : {
4580 692 : GDALDatasetH hDS = nullptr;
4581 692 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4582 : }
4583 : #endif
4584 :
4585 19026 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4586 : {
4587 12054 : std::string osHint;
4588 12054 : const CPLStringList aosVSIFSPrefixes(VSIFileManager::GetPrefixes());
4589 186752 : for (const char *pszFSPrefix : aosVSIFSPrefixes)
4590 : {
4591 180732 : auto poFS = VSIFileManager::GetHandler(pszFSPrefix);
4592 180732 : if (poFS)
4593 : {
4594 180732 : osHint = poFS->GetHintForPotentiallyRecognizedPath(pszFilename);
4595 180732 : if (!osHint.empty())
4596 : {
4597 14 : osHint = " Changing the filename to " + osHint +
4598 7 : " may help it to be recognized.";
4599 7 : break;
4600 : }
4601 : }
4602 : }
4603 :
4604 6027 : if (nDriverCount == 0)
4605 : {
4606 0 : CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4607 : }
4608 6027 : else if (poMissingPluginDriver)
4609 : {
4610 0 : std::string osMsg("`");
4611 0 : osMsg += pszFilename;
4612 : osMsg += "' not recognized as being in a supported file format. "
4613 0 : "It could have been recognized by driver ";
4614 0 : osMsg += poMissingPluginDriver->GetDescription();
4615 0 : osMsg += ", but plugin ";
4616 : osMsg +=
4617 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4618 :
4619 0 : CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4620 : }
4621 : // Check to see if there was a filesystem error, and report it if so.
4622 : // If not, return a more generic error.
4623 6027 : else if (!osHint.empty() && VSIGetLastErrorNo() == VSIE_FileError)
4624 : {
4625 3 : CPLError(CE_Failure, CPLE_FileIO, "%s.%s", VSIGetLastErrorMsg(),
4626 : osHint.c_str());
4627 : }
4628 6024 : else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4629 : {
4630 518 : if (oOpenInfo.bStatOK)
4631 : {
4632 513 : CPLError(CE_Failure, CPLE_OpenFailed,
4633 : "`%s' not recognized as being in a supported file "
4634 : "format.%s",
4635 : pszFilename, osHint.c_str());
4636 : }
4637 : else
4638 : {
4639 : // If Stat failed and no VSI error was set, assume it is because
4640 : // the file did not exist on the filesystem.
4641 5 : CPLError(CE_Failure, CPLE_OpenFailed,
4642 : "`%s' does not exist in the file system, "
4643 : "and is not recognized as a supported dataset name.%s",
4644 : pszFilename, osHint.c_str());
4645 : }
4646 : }
4647 : }
4648 :
4649 19026 : return nullptr;
4650 : }
4651 :
4652 : /************************************************************************/
4653 : /* GDALOpenShared() */
4654 : /************************************************************************/
4655 :
4656 : /**
4657 : * \brief Open a raster file as a GDALDataset.
4658 : *
4659 : * This function works the same as GDALOpen(), but allows the sharing of
4660 : * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4661 : *
4662 : * In particular, GDALOpenShared() will first consult its list of currently
4663 : * open and shared GDALDataset's, and if the GetDescription() name for one
4664 : * exactly matches the pszFilename passed to GDALOpenShared() it will be
4665 : * referenced and returned.
4666 : *
4667 : * If GDALOpenShared() is called on the same
4668 : * pszFilename from two different threads, a different GDALDataset object will
4669 : * be returned as it is not safe to use the same dataset from different threads,
4670 : * unless the user does explicitly use mutexes in its code.
4671 : *
4672 : * For drivers supporting the VSI virtual file API, it is possible to open a
4673 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4674 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4675 : * server (see VSIInstallCurlFileHandler())
4676 : *
4677 : * \sa GDALOpen()
4678 : * \sa GDALOpenEx()
4679 : *
4680 : * @param pszFilename the name of the file to access. In the case of
4681 : * exotic drivers this may not refer to a physical file, but instead contain
4682 : * information for the driver on how to access a dataset. It should be in
4683 : * UTF-8 encoding.
4684 : *
4685 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
4686 : * drivers support only read only access.
4687 : *
4688 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4689 : * this handle can be cast to a GDALDataset *.
4690 : */
4691 :
4692 5209 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4693 : GDALAccess eAccess)
4694 : {
4695 5209 : VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4696 5209 : return GDALOpenEx(pszFilename,
4697 : GDAL_OF_RASTER |
4698 : (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4699 : GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4700 5209 : nullptr, nullptr, nullptr);
4701 : }
4702 :
4703 : /************************************************************************/
4704 : /* GDALClose() */
4705 : /************************************************************************/
4706 :
4707 : /**
4708 : * \brief Close GDAL dataset.
4709 : *
4710 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4711 : * using the C++ "delete" operator, recovering all dataset related resources.
4712 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4713 : * dereferenced, and closed only if the referenced count has dropped below 1.
4714 : *
4715 : * @param hDS The dataset to close, or nullptr.
4716 : * @return CE_None in case of success (return value since GDAL 3.7). On a
4717 : * shared dataset whose reference count is not dropped below 1, CE_None will
4718 : * be returned.
4719 : *
4720 : * @see GDALCloseEx()
4721 : */
4722 :
4723 88154 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4724 :
4725 : {
4726 88154 : return GDALCloseEx(hDS, nullptr, nullptr);
4727 : }
4728 :
4729 : /************************************************************************/
4730 : /* GDALCloseEx() */
4731 : /************************************************************************/
4732 :
4733 : /**
4734 : * \brief Close GDAL dataset.
4735 : *
4736 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4737 : * using the C++ "delete" operator, recovering all dataset related resources.
4738 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4739 : * dereferenced, and closed only if the referenced count has dropped below 1.
4740 : *
4741 : * This function may report progress if a progress
4742 : * callback if provided in the pfnProgress argument and if the dataset returns
4743 : * true for GDALDataset::GetCloseReportsProgress()
4744 :
4745 : * @param hDS The dataset to close, or nullptr
4746 : * @param pfnProgress Progress callback, or nullptr
4747 : * @param pProgressData User data of progress callback, or nullptr
4748 : *
4749 : * @return CE_None in case of success. On a
4750 : * shared dataset whose reference count is not dropped below 1, CE_None will
4751 : * be returned.
4752 : *
4753 : * @since GDAL 3.13
4754 : * @see GDALClose()
4755 : */
4756 :
4757 92625 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4758 : void *pProgressData)
4759 : {
4760 92625 : if (!hDS)
4761 405 : return CE_None;
4762 :
4763 : #ifdef OGRAPISPY_ENABLED
4764 92220 : if (bOGRAPISpyEnabled)
4765 11 : OGRAPISpyPreClose(hDS);
4766 : #endif
4767 :
4768 92220 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4769 :
4770 92220 : if (poDS->GetShared())
4771 : {
4772 : /* --------------------------------------------------------------------
4773 : */
4774 : /* If this file is in the shared dataset list then dereference */
4775 : /* it, and only delete/remote it if the reference count has */
4776 : /* dropped to zero. */
4777 : /* --------------------------------------------------------------------
4778 : */
4779 233 : if (poDS->Dereference() > 0)
4780 14 : return CE_None;
4781 : }
4782 :
4783 92206 : CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4784 92206 : delete poDS;
4785 :
4786 : #ifdef OGRAPISPY_ENABLED
4787 92206 : if (bOGRAPISpyEnabled)
4788 11 : OGRAPISpyPostClose();
4789 : #endif
4790 92206 : return eErr;
4791 : }
4792 :
4793 : /************************************************************************/
4794 : /* GDALDumpOpenDataset() */
4795 : /************************************************************************/
4796 :
4797 0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4798 : {
4799 0 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4800 0 : FILE *fp = static_cast<FILE *>(user_data);
4801 0 : GDALDataset *poDS = psStruct->poDS;
4802 :
4803 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4804 0 : ? "DriverIsNULL"
4805 0 : : poDS->GetDriver()->GetDescription();
4806 :
4807 0 : poDS->Reference();
4808 0 : CPL_IGNORE_RET_VAL(
4809 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4810 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName,
4811 0 : static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4812 : poDS->GetRasterYSize(), poDS->GetRasterCount(),
4813 0 : poDS->GetDescription()));
4814 :
4815 0 : return TRUE;
4816 : }
4817 :
4818 0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4819 : {
4820 :
4821 : // Don't list shared datasets. They have already been listed by
4822 : // GDALDumpOpenSharedDatasetsForeach.
4823 0 : if (poDS->GetShared())
4824 0 : return TRUE;
4825 :
4826 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4827 0 : ? "DriverIsNULL"
4828 0 : : poDS->GetDriver()->GetDescription();
4829 :
4830 0 : poDS->Reference();
4831 0 : CPL_IGNORE_RET_VAL(
4832 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4833 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4834 : poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4835 0 : poDS->GetRasterCount(), poDS->GetDescription()));
4836 :
4837 0 : return TRUE;
4838 : }
4839 :
4840 : /**
4841 : * \brief List open datasets.
4842 : *
4843 : * Dumps a list of all open datasets (shared or not) to the indicated
4844 : * text file (may be stdout or stderr). This function is primarily intended
4845 : * to assist in debugging "dataset leaks" and reference counting issues.
4846 : * The information reported includes the dataset name, referenced count,
4847 : * shared status, driver name, size, and band count.
4848 : */
4849 :
4850 272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4851 :
4852 : {
4853 272 : VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4854 :
4855 544 : CPLMutexHolderD(&hDLMutex);
4856 :
4857 272 : if (poAllDatasetMap == nullptr)
4858 272 : return 0;
4859 :
4860 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4861 :
4862 0 : for (const auto &oIter : *poAllDatasetMap)
4863 : {
4864 0 : GDALDumpOpenDatasetsForeach(oIter.first, fp);
4865 : }
4866 :
4867 0 : if (phSharedDatasetSet != nullptr)
4868 : {
4869 0 : CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4870 : fp);
4871 : }
4872 0 : return static_cast<int>(poAllDatasetMap->size());
4873 : }
4874 :
4875 : /************************************************************************/
4876 : /* BeginAsyncReader() */
4877 : /************************************************************************/
4878 :
4879 : /**
4880 : * \brief Sets up an asynchronous data request
4881 : *
4882 : * This method establish an asynchronous raster read request for the
4883 : * indicated window on the dataset into the indicated buffer. The parameters
4884 : * for windowing, buffer size, buffer type and buffer organization are similar
4885 : * to those for GDALDataset::RasterIO(); however, this call only launches
4886 : * the request and filling the buffer is accomplished via calls to
4887 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4888 : *
4889 : * Once all processing for the created session is complete, or if no further
4890 : * refinement of the request is required, the GDALAsyncReader object should
4891 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4892 : *
4893 : * Note that the data buffer (pData) will potentially continue to be
4894 : * updated as long as the session lives, but it is not deallocated when
4895 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4896 : * should be deallocated by the application at that point.
4897 : *
4898 : * Additional information on asynchronous IO in GDAL may be found at:
4899 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4900 : *
4901 : * This method is the same as the C GDALBeginAsyncReader() function.
4902 : *
4903 : * @param nXOff The pixel offset to the top left corner of the region
4904 : * of the band to be accessed. This would be zero to start from the left side.
4905 : *
4906 : * @param nYOff The line offset to the top left corner of the region
4907 : * of the band to be accessed. This would be zero to start from the top.
4908 : *
4909 : * @param nXSize The width of the region of the band to be accessed in pixels.
4910 : *
4911 : * @param nYSize The height of the region of the band to be accessed in lines.
4912 : *
4913 : * @param pBuf The buffer into which the data should be read. This buffer must
4914 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4915 : * It is organized in left to right,top to bottom pixel order. Spacing is
4916 : * controlled by the nPixelSpace, and nLineSpace parameters.
4917 : *
4918 : * @param nBufXSize the width of the buffer image into which the desired region
4919 : * is to be read, or from which it is to be written.
4920 : *
4921 : * @param nBufYSize the height of the buffer image into which the desired
4922 : * region is to be read, or from which it is to be written.
4923 : *
4924 : * @param eBufType the type of the pixel values in the pData data buffer. The
4925 : * pixel values will automatically be translated to/from the GDALRasterBand
4926 : * data type as needed.
4927 : *
4928 : * @param nBandCount the number of bands being read or written.
4929 : *
4930 : * @param panBandMap the list of nBandCount band numbers being read/written.
4931 : * Note band numbers are 1 based. This may be NULL to select the first
4932 : * nBandCount bands.
4933 : *
4934 : * @param nPixelSpace The byte offset from the start of one pixel value in
4935 : * pData to the start of the next pixel value within a scanline. If defaulted
4936 : * (0) the size of the datatype eBufType is used.
4937 : *
4938 : * @param nLineSpace The byte offset from the start of one scanline in
4939 : * pData to the start of the next. If defaulted the size of the datatype
4940 : * eBufType * nBufXSize is used.
4941 : *
4942 : * @param nBandSpace the byte offset from the start of one bands data to the
4943 : * start of the next. If defaulted (zero) the value will be
4944 : * nLineSpace * nBufYSize implying band sequential organization
4945 : * of the data buffer.
4946 : *
4947 : * @param papszOptions Driver specific control options in a string list or NULL.
4948 : * Consult driver documentation for options supported.
4949 : *
4950 : * @return The GDALAsyncReader object representing the request.
4951 : */
4952 :
4953 1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
4954 : int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4955 : int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4956 : int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4957 : {
4958 : // See gdaldefaultasync.cpp
4959 :
4960 1 : return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4961 : nBufXSize, nBufYSize, eBufType, nBandCount,
4962 : panBandMap, nPixelSpace, nLineSpace,
4963 1 : nBandSpace, papszOptions);
4964 : }
4965 :
4966 : /************************************************************************/
4967 : /* GDALBeginAsyncReader() */
4968 : /************************************************************************/
4969 :
4970 : /**
4971 : * \brief Sets up an asynchronous data request
4972 : *
4973 : * This method establish an asynchronous raster read request for the
4974 : * indicated window on the dataset into the indicated buffer. The parameters
4975 : * for windowing, buffer size, buffer type and buffer organization are similar
4976 : * to those for GDALDataset::RasterIO(); however, this call only launches
4977 : * the request and filling the buffer is accomplished via calls to
4978 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4979 : *
4980 : * Once all processing for the created session is complete, or if no further
4981 : * refinement of the request is required, the GDALAsyncReader object should
4982 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4983 : *
4984 : * Note that the data buffer (pData) will potentially continue to be
4985 : * updated as long as the session lives, but it is not deallocated when
4986 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4987 : * should be deallocated by the application at that point.
4988 : *
4989 : * Additional information on asynchronous IO in GDAL may be found at:
4990 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4991 : *
4992 : * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4993 : *
4994 : * @param hDS handle to the dataset object.
4995 : *
4996 : * @param nXOff The pixel offset to the top left corner of the region
4997 : * of the band to be accessed. This would be zero to start from the left side.
4998 : *
4999 : * @param nYOff The line offset to the top left corner of the region
5000 : * of the band to be accessed. This would be zero to start from the top.
5001 : *
5002 : * @param nXSize The width of the region of the band to be accessed in pixels.
5003 : *
5004 : * @param nYSize The height of the region of the band to be accessed in lines.
5005 : *
5006 : * @param pBuf The buffer into which the data should be read. This buffer must
5007 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
5008 : * It is organized in left to right,top to bottom pixel order. Spacing is
5009 : * controlled by the nPixelSpace, and nLineSpace parameters.
5010 : *
5011 : * @param nBufXSize the width of the buffer image into which the desired region
5012 : * is to be read, or from which it is to be written.
5013 : *
5014 : * @param nBufYSize the height of the buffer image into which the desired
5015 : * region is to be read, or from which it is to be written.
5016 : *
5017 : * @param eBufType the type of the pixel values in the pData data buffer. The
5018 : * pixel values will automatically be translated to/from the GDALRasterBand
5019 : * data type as needed.
5020 : *
5021 : * @param nBandCount the number of bands being read or written.
5022 : *
5023 : * @param panBandMap the list of nBandCount band numbers being read/written.
5024 : * Note band numbers are 1 based. This may be NULL to select the first
5025 : * nBandCount bands.
5026 : *
5027 : * @param nPixelSpace The byte offset from the start of one pixel value in
5028 : * pData to the start of the next pixel value within a scanline. If defaulted
5029 : * (0) the size of the datatype eBufType is used.
5030 : *
5031 : * @param nLineSpace The byte offset from the start of one scanline in
5032 : * pData to the start of the next. If defaulted the size of the datatype
5033 : * eBufType * nBufXSize is used.
5034 : *
5035 : * @param nBandSpace the byte offset from the start of one bands data to the
5036 : * start of the next. If defaulted (zero) the value will be
5037 : * nLineSpace * nBufYSize implying band sequential organization
5038 : * of the data buffer.
5039 : *
5040 : * @param papszOptions Driver specific control options in a string list or NULL.
5041 : * Consult driver documentation for options supported.
5042 : *
5043 : * @return handle representing the request.
5044 : */
5045 :
5046 2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5047 : GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5048 : int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5049 : int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5050 : CSLConstList papszOptions)
5051 :
5052 : {
5053 2 : VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5054 : return static_cast<GDALAsyncReaderH>(
5055 2 : GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5056 : nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5057 : nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5058 2 : const_cast<char **>(papszOptions)));
5059 : }
5060 :
5061 : /************************************************************************/
5062 : /* EndAsyncReader() */
5063 : /************************************************************************/
5064 :
5065 : /**
5066 : * End asynchronous request.
5067 : *
5068 : * This method destroys an asynchronous io request and recovers all
5069 : * resources associated with it.
5070 : *
5071 : * This method is the same as the C function GDALEndAsyncReader().
5072 : *
5073 : * @param poARIO pointer to a GDALAsyncReader
5074 : */
5075 :
5076 1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5077 : {
5078 1 : delete poARIO;
5079 1 : }
5080 :
5081 : /************************************************************************/
5082 : /* GDALEndAsyncReader() */
5083 : /************************************************************************/
5084 :
5085 : /**
5086 : * End asynchronous request.
5087 : *
5088 : * This method destroys an asynchronous io request and recovers all
5089 : * resources associated with it.
5090 : *
5091 : * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5092 : *
5093 : * @param hDS handle to the dataset object.
5094 : * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5095 : */
5096 :
5097 1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5098 : GDALAsyncReaderH hAsyncReaderH)
5099 : {
5100 1 : VALIDATE_POINTER0(hDS, "GDALDataset");
5101 1 : VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5102 1 : GDALDataset::FromHandle(hDS)->EndAsyncReader(
5103 1 : static_cast<GDALAsyncReader *>(hAsyncReaderH));
5104 : }
5105 :
5106 : /************************************************************************/
5107 : /* CloseDependentDatasets() */
5108 : /************************************************************************/
5109 :
5110 : /**
5111 : * Drop references to any other datasets referenced by this dataset.
5112 : *
5113 : * This method should release any reference to other datasets (e.g. a VRT
5114 : * dataset to its sources), but not close the current dataset itself.
5115 : *
5116 : * If at least, one reference to a dependent dataset has been dropped,
5117 : * this method should return TRUE. Otherwise it *should* return FALSE.
5118 : * (Failure to return the proper value might result in infinite loop)
5119 : *
5120 : * This method can be called several times on a given dataset. After
5121 : * the first time, it should not do anything and return FALSE.
5122 : *
5123 : * The driver implementation may choose to destroy its raster bands,
5124 : * so be careful not to call any method on the raster bands afterwards.
5125 : *
5126 : * Basically the only safe action you can do after calling
5127 : * CloseDependentDatasets() is to call the destructor.
5128 : *
5129 : * Note: the only legitimate caller of CloseDependentDatasets() is
5130 : * GDALDriverManager::~GDALDriverManager()
5131 : *
5132 : * @return TRUE if at least one reference to another dataset has been dropped.
5133 : */
5134 19966 : int GDALDataset::CloseDependentDatasets()
5135 : {
5136 19966 : return oOvManager.CloseDependentDatasets();
5137 : }
5138 :
5139 : /************************************************************************/
5140 : /* ReportError() */
5141 : /************************************************************************/
5142 :
5143 : #ifndef DOXYGEN_XML
5144 : /**
5145 : * \brief Emits an error related to a dataset.
5146 : *
5147 : * This function is a wrapper for regular CPLError(). The only difference
5148 : * with CPLError() is that it prepends the error message with the dataset
5149 : * name.
5150 : *
5151 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5152 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5153 : * @param fmt a printf() style format string. Any additional arguments
5154 : * will be treated as arguments to fill in this format in a manner
5155 : * similar to printf().
5156 : *
5157 : */
5158 :
5159 105 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5160 : const char *fmt, ...) const
5161 : {
5162 : va_list args;
5163 105 : va_start(args, fmt);
5164 105 : ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5165 105 : va_end(args);
5166 105 : }
5167 :
5168 : /**
5169 : * \brief Emits an error related to a dataset (static method)
5170 : *
5171 : * This function is a wrapper for regular CPLError(). The only difference
5172 : * with CPLError() is that it prepends the error message with the dataset
5173 : * name.
5174 : *
5175 : * @param pszDSName dataset name.
5176 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5177 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5178 : * @param fmt a printf() style format string. Any additional arguments
5179 : * will be treated as arguments to fill in this format in a manner
5180 : * similar to printf().
5181 : *
5182 : * @since GDAL 3.2.0
5183 : */
5184 :
5185 186 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5186 : CPLErrorNum err_no, const char *fmt, ...)
5187 : {
5188 : va_list args;
5189 186 : va_start(args, fmt);
5190 186 : ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5191 186 : va_end(args);
5192 186 : }
5193 :
5194 291 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5195 : CPLErrorNum err_no, const char *fmt,
5196 : va_list args)
5197 : {
5198 291 : pszDSName = CPLGetFilename(pszDSName);
5199 291 : if (pszDSName[0] != '\0')
5200 : {
5201 274 : CPLError(eErrClass, err_no, "%s",
5202 548 : std::string(pszDSName)
5203 274 : .append(": ")
5204 548 : .append(CPLString().vPrintf(fmt, args))
5205 : .c_str());
5206 : }
5207 : else
5208 : {
5209 17 : CPLErrorV(eErrClass, err_no, fmt, args);
5210 : }
5211 291 : }
5212 : #endif
5213 :
5214 : /************************************************************************/
5215 : /* GetMetadata() */
5216 : /************************************************************************/
5217 74885 : CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5218 : {
5219 : #ifndef WITHOUT_DERIVED
5220 74885 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5221 : {
5222 10 : oDerivedMetadataList.Clear();
5223 :
5224 : // First condition: at least one raster band.
5225 10 : if (GetRasterCount() > 0)
5226 : {
5227 : // Check if there is at least one complex band.
5228 10 : bool hasAComplexBand = false;
5229 :
5230 19 : for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5231 : {
5232 11 : if (GDALDataTypeIsComplex(
5233 11 : GetRasterBand(rasterId)->GetRasterDataType()))
5234 : {
5235 2 : hasAComplexBand = true;
5236 2 : break;
5237 : }
5238 : }
5239 :
5240 10 : unsigned int nbSupportedDerivedDS = 0;
5241 : const DerivedDatasetDescription *poDDSDesc =
5242 10 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5243 :
5244 10 : int nNumDataset = 1;
5245 80 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5246 : ++derivedId)
5247 : {
5248 126 : if (hasAComplexBand ||
5249 126 : CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5250 : "complex")
5251 : {
5252 : oDerivedMetadataList.SetNameValue(
5253 : CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5254 : CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5255 22 : poDDSDesc[derivedId].pszDatasetName,
5256 22 : GetDescription()));
5257 :
5258 : CPLString osDesc(
5259 : CPLSPrintf("%s from %s",
5260 22 : poDDSDesc[derivedId].pszDatasetDescription,
5261 22 : GetDescription()));
5262 : oDerivedMetadataList.SetNameValue(
5263 : CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5264 22 : osDesc.c_str());
5265 :
5266 22 : nNumDataset++;
5267 : }
5268 : }
5269 : }
5270 10 : return oDerivedMetadataList.List();
5271 : }
5272 : #endif
5273 :
5274 74875 : return GDALMajorObject::GetMetadata(pszDomain);
5275 : }
5276 :
5277 : // clang-format off
5278 :
5279 : /**
5280 : * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5281 : * \brief Set metadata.
5282 : *
5283 : * CAUTION: depending on the format, older values of the updated information
5284 : * might still be found in the file in a "ghost" state, even if no longer
5285 : * accessible through the GDAL API. This is for example the case of the GTiff
5286 : * format (this is not a exhaustive list)
5287 : *
5288 : * The C function GDALSetMetadata() does the same thing as this method.
5289 : *
5290 : * @param papszMetadata the metadata in name=value string list format to
5291 : * apply.
5292 : * @param pszDomain the domain of interest. Use "" or NULL for the default
5293 : * domain.
5294 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5295 : * metadata has been accepted, but is likely not maintained persistently
5296 : * by the underlying object between sessions.
5297 : */
5298 :
5299 : /**
5300 : * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5301 : * \brief Set single metadata item.
5302 : *
5303 : * CAUTION: depending on the format, older values of the updated information
5304 : * might still be found in the file in a "ghost" state, even if no longer
5305 : * accessible through the GDAL API. This is for example the case of the GTiff
5306 : * format (this is not a exhaustive list)
5307 : *
5308 : * The C function GDALSetMetadataItem() does the same thing as this method.
5309 : *
5310 : * @param pszName the key for the metadata item to fetch.
5311 : * @param pszValue the value to assign to the key.
5312 : * @param pszDomain the domain to set within, use NULL for the default domain.
5313 : *
5314 : * @return CE_None on success, or an error code on failure.
5315 : */
5316 :
5317 : // clang-format on
5318 :
5319 : /************************************************************************/
5320 : /* GetMetadataDomainList() */
5321 : /************************************************************************/
5322 :
5323 1120 : char **GDALDataset::GetMetadataDomainList()
5324 : {
5325 1120 : char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5326 :
5327 : // Ensure that we do not duplicate DERIVED domain.
5328 1267 : if (GetRasterCount() > 0 &&
5329 147 : CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5330 : {
5331 : currentDomainList =
5332 147 : CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5333 : }
5334 1120 : return currentDomainList;
5335 : }
5336 :
5337 : /************************************************************************/
5338 : /* GetDriverName() */
5339 : /************************************************************************/
5340 :
5341 : /** Return driver name.
5342 : * @return driver name.
5343 : */
5344 2670 : const char *GDALDataset::GetDriverName() const
5345 : {
5346 2670 : if (poDriver)
5347 2656 : return poDriver->GetDescription();
5348 14 : return "";
5349 : }
5350 :
5351 : /************************************************************************/
5352 : /* GDALDatasetReleaseResultSet() */
5353 : /************************************************************************/
5354 :
5355 : /**
5356 : \brief Release results of ExecuteSQL().
5357 :
5358 : This function should only be used to deallocate OGRLayers resulting from
5359 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
5360 : results set before destroying the GDALDataset may cause errors.
5361 :
5362 : This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5363 :
5364 :
5365 : @param hDS the dataset handle.
5366 : @param hLayer the result of a previous ExecuteSQL() call.
5367 :
5368 : */
5369 3563 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5370 :
5371 : {
5372 3563 : VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5373 :
5374 : #ifdef OGRAPISPY_ENABLED
5375 3563 : if (bOGRAPISpyEnabled)
5376 6 : OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5377 : #endif
5378 :
5379 7126 : GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5380 3563 : OGRLayer::FromHandle(hLayer));
5381 : }
5382 :
5383 : /************************************************************************/
5384 : /* GDALDatasetGetLayerCount() */
5385 : /************************************************************************/
5386 :
5387 : /**
5388 : \brief Get the number of layers in this dataset.
5389 :
5390 : This function is the same as the C++ method GDALDataset::GetLayerCount()
5391 :
5392 :
5393 : @param hDS the dataset handle.
5394 : @return layer count.
5395 : */
5396 :
5397 3480 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5398 :
5399 : {
5400 3480 : VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5401 :
5402 : #ifdef OGRAPISPY_ENABLED
5403 3480 : if (bOGRAPISpyEnabled)
5404 2 : OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5405 : #endif
5406 :
5407 3480 : return GDALDataset::FromHandle(hDS)->GetLayerCount();
5408 : }
5409 :
5410 : /************************************************************************/
5411 : /* GDALDatasetGetLayer() */
5412 : /************************************************************************/
5413 :
5414 : /**
5415 : \brief Fetch a layer by index.
5416 :
5417 : The returned layer remains owned by the
5418 : GDALDataset and should not be deleted by the application.
5419 :
5420 : This function is the same as the C++ method GDALDataset::GetLayer()
5421 :
5422 :
5423 : @param hDS the dataset handle.
5424 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5425 :
5426 : @return the layer, or NULL if iLayer is out of range or an error occurs.
5427 : */
5428 :
5429 11034 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5430 :
5431 : {
5432 11034 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5433 :
5434 : OGRLayerH hLayer =
5435 11034 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5436 :
5437 : #ifdef OGRAPISPY_ENABLED
5438 11034 : if (bOGRAPISpyEnabled)
5439 3 : OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5440 : #endif
5441 :
5442 11034 : return hLayer;
5443 : }
5444 :
5445 : /************************************************************************/
5446 : /* GDALDatasetGetLayerByName() */
5447 : /************************************************************************/
5448 :
5449 : /**
5450 : \brief Fetch a layer by name.
5451 :
5452 : The returned layer remains owned by the
5453 : GDALDataset and should not be deleted by the application.
5454 :
5455 : This function is the same as the C++ method GDALDataset::GetLayerByName()
5456 :
5457 :
5458 : @param hDS the dataset handle.
5459 : @param pszName the layer name of the layer to fetch.
5460 :
5461 : @return the layer, or NULL if Layer is not found or an error occurs.
5462 : */
5463 :
5464 3555 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5465 :
5466 : {
5467 3555 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5468 :
5469 3555 : OGRLayerH hLayer = OGRLayer::ToHandle(
5470 3555 : GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5471 :
5472 : #ifdef OGRAPISPY_ENABLED
5473 3555 : if (bOGRAPISpyEnabled)
5474 4 : OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5475 : #endif
5476 :
5477 3555 : return hLayer;
5478 : }
5479 :
5480 : /************************************************************************/
5481 : /* GDALDatasetIsLayerPrivate() */
5482 : /************************************************************************/
5483 :
5484 : /**
5485 : \brief Returns true if the layer at the specified index is deemed a private or
5486 : system table, or an internal detail only.
5487 :
5488 : This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5489 :
5490 : @since GDAL 3.4
5491 :
5492 : @param hDS the dataset handle.
5493 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5494 :
5495 : @return true if the layer is a private or system table.
5496 : */
5497 :
5498 91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5499 :
5500 : {
5501 91 : VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5502 :
5503 91 : const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5504 :
5505 91 : return res ? 1 : 0;
5506 : }
5507 :
5508 : /************************************************************************/
5509 : /* GetLayerIndex() */
5510 : /************************************************************************/
5511 :
5512 : /**
5513 : \brief Returns the index of the layer specified by name.
5514 :
5515 : @since GDAL 3.12
5516 :
5517 : @param pszName layer name (not NULL)
5518 :
5519 : @return an index >= 0, or -1 if not found.
5520 : */
5521 :
5522 3 : int GDALDataset::GetLayerIndex(const char *pszName) const
5523 : {
5524 3 : const int nLayerCount = GetLayerCount();
5525 3 : int iMatch = -1;
5526 6 : for (int i = 0; i < nLayerCount; ++i)
5527 : {
5528 5 : if (const auto poLayer = GetLayer(i))
5529 : {
5530 5 : const char *pszLayerName = poLayer->GetDescription();
5531 5 : if (strcmp(pszName, pszLayerName) == 0)
5532 : {
5533 2 : iMatch = i;
5534 2 : break;
5535 : }
5536 3 : else if (EQUAL(pszName, pszLayerName))
5537 : {
5538 0 : iMatch = i;
5539 : }
5540 : }
5541 : }
5542 3 : return iMatch;
5543 : }
5544 :
5545 : /************************************************************************/
5546 : /* GDALDatasetDeleteLayer() */
5547 : /************************************************************************/
5548 :
5549 : /**
5550 : \brief Delete the indicated layer from the datasource.
5551 :
5552 : If this function is supported
5553 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5554 :
5555 : This method is the same as the C++ method GDALDataset::DeleteLayer().
5556 :
5557 :
5558 : @param hDS the dataset handle.
5559 : @param iLayer the index of the layer to delete.
5560 :
5561 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5562 : layers is not supported for this datasource.
5563 :
5564 : */
5565 41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5566 :
5567 : {
5568 41 : VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5569 :
5570 : #ifdef OGRAPISPY_ENABLED
5571 41 : if (bOGRAPISpyEnabled)
5572 2 : OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5573 : #endif
5574 :
5575 41 : return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5576 : }
5577 :
5578 : /************************************************************************/
5579 : /* CreateLayer() */
5580 : /************************************************************************/
5581 :
5582 : /**
5583 : \brief This method attempts to create a new layer on the dataset with the
5584 : indicated name, coordinate system, geometry type.
5585 :
5586 : The papszOptions argument
5587 : can be used to control driver specific creation options. These options are
5588 : normally documented in the format specific documentation.
5589 : That function will try to validate the creation option list passed to the
5590 : driver with the GDALValidateCreationOptions() method. This check can be
5591 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5592 : to NO.
5593 :
5594 : Drivers should extend the ICreateLayer() method and not
5595 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5596 : delegating the actual work to ICreateLayer().
5597 :
5598 : This method is the same as the C function GDALDatasetCreateLayer() and the
5599 : deprecated OGR_DS_CreateLayer().
5600 :
5601 : Example:
5602 :
5603 : \code{.cpp}
5604 : #include "gdal.h"
5605 : #include "cpl_string.h"
5606 :
5607 : ...
5608 :
5609 : OGRLayer *poLayer;
5610 : char **papszOptions;
5611 :
5612 : if( !poDS->TestCapability( ODsCCreateLayer ) )
5613 : {
5614 : ...
5615 : }
5616 :
5617 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5618 : poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5619 : papszOptions );
5620 : CSLDestroy( papszOptions );
5621 :
5622 : if( poLayer == NULL )
5623 : {
5624 : ...
5625 : }
5626 : \endcode
5627 :
5628 : @param pszName the name for the new layer. This should ideally not
5629 : match any existing layer on the datasource.
5630 : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
5631 : no coordinate system is available.
5632 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5633 : are no constraints on the types geometry to be written.
5634 : @param papszOptions a StringList of name=value options. Options are driver
5635 : specific.
5636 :
5637 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5638 :
5639 : */
5640 :
5641 8475 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5642 : const OGRSpatialReference *poSpatialRef,
5643 : OGRwkbGeometryType eGType,
5644 : CSLConstList papszOptions)
5645 :
5646 : {
5647 8475 : if (eGType == wkbNone)
5648 : {
5649 532 : return CreateLayer(pszName, nullptr, papszOptions);
5650 : }
5651 : else
5652 : {
5653 15886 : OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5654 7943 : oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5655 7943 : return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5656 : }
5657 : }
5658 :
5659 : /**
5660 : \brief This method attempts to create a new layer on the dataset with the
5661 : indicated name and geometry field definition.
5662 :
5663 : When poGeomFieldDefn is not null, most drivers should honor
5664 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5665 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5666 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5667 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5668 : very few currently.
5669 :
5670 : Note that even if a geometry coordinate precision is set and a driver honors the
5671 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5672 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5673 : with the coordinate precision. That is they are assumed to be valid once their
5674 : coordinates are rounded to it. If it might not be the case, the user may set
5675 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5676 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5677 : the passed geometries.
5678 :
5679 : The papszOptions argument
5680 : can be used to control driver specific creation options. These options are
5681 : normally documented in the format specific documentation.
5682 : This function will try to validate the creation option list passed to the
5683 : driver with the GDALValidateCreationOptions() method. This check can be
5684 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5685 : to NO.
5686 :
5687 : Drivers should extend the ICreateLayer() method and not
5688 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5689 : delegating the actual work to ICreateLayer().
5690 :
5691 : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5692 :
5693 : @param pszName the name for the new layer. This should ideally not
5694 : match any existing layer on the datasource.
5695 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
5696 : or NULL if there is no geometry field.
5697 : @param papszOptions a StringList of name=value options. Options are driver
5698 : specific.
5699 :
5700 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5701 : @since 3.9
5702 :
5703 : */
5704 :
5705 10009 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5706 : const OGRGeomFieldDefn *poGeomFieldDefn,
5707 : CSLConstList papszOptions)
5708 :
5709 : {
5710 10009 : if (CPLTestBool(
5711 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5712 : {
5713 10009 : ValidateLayerCreationOptions(papszOptions);
5714 : }
5715 :
5716 : OGRLayer *poLayer;
5717 10009 : if (poGeomFieldDefn)
5718 : {
5719 9043 : OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5720 9137 : if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5721 94 : !TestCapability(ODsCCurveGeometries))
5722 : {
5723 23 : oGeomFieldDefn.SetType(
5724 : OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5725 : }
5726 :
5727 9043 : poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5728 : }
5729 : else
5730 : {
5731 966 : poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5732 : }
5733 : #ifdef DEBUG
5734 10080 : if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5735 71 : !poLayer->TestCapability(OLCCurveGeometries))
5736 : {
5737 0 : CPLError(CE_Warning, CPLE_AppDefined,
5738 : "Inconsistent driver: Layer geometry type is non-linear, but "
5739 : "TestCapability(OLCCurveGeometries) returns FALSE.");
5740 : }
5741 : #endif
5742 :
5743 10009 : return poLayer;
5744 : }
5745 :
5746 : //! @cond Doxygen_Suppress
5747 :
5748 : // Technical override to avoid ambiguous choice between the old and new
5749 : // new CreateLayer() signatures.
5750 39 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5751 : {
5752 78 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5753 78 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5754 : }
5755 :
5756 : // Technical override to avoid ambiguous choice between the old and new
5757 : // new CreateLayer() signatures.
5758 1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5759 : {
5760 2 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5761 2 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5762 : }
5763 :
5764 : //!@endcond
5765 :
5766 : /************************************************************************/
5767 : /* GDALDatasetCreateLayer() */
5768 : /************************************************************************/
5769 :
5770 : /**
5771 : \brief This function attempts to create a new layer on the dataset with the
5772 : indicated name, coordinate system, geometry type.
5773 :
5774 : The papszOptions argument can be used to control driver specific creation
5775 : options. These options are normally documented in the format specific
5776 : documentation.
5777 :
5778 : This method is the same as the C++ method GDALDataset::CreateLayer().
5779 :
5780 : Example:
5781 :
5782 : \code{.c}
5783 : #include "gdal.h"
5784 : #include "cpl_string.h"
5785 :
5786 : ...
5787 :
5788 : OGRLayerH hLayer;
5789 : char **papszOptions;
5790 :
5791 : if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5792 : {
5793 : ...
5794 : }
5795 :
5796 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5797 : hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5798 : papszOptions );
5799 : CSLDestroy( papszOptions );
5800 :
5801 : if( hLayer == NULL )
5802 : {
5803 : ...
5804 : }
5805 : \endcode
5806 :
5807 :
5808 : @param hDS the dataset handle
5809 : @param pszName the name for the new layer. This should ideally not
5810 : match any existing layer on the datasource.
5811 : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
5812 : no coordinate system is available.
5813 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5814 : are no constraints on the types geometry to be written.
5815 : @param papszOptions a StringList of name=value options. Options are driver
5816 : specific.
5817 :
5818 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5819 :
5820 : */
5821 :
5822 6601 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5823 : OGRSpatialReferenceH hSpatialRef,
5824 : OGRwkbGeometryType eGType,
5825 : CSLConstList papszOptions)
5826 :
5827 : {
5828 6601 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5829 :
5830 6601 : if (pszName == nullptr)
5831 : {
5832 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5833 : "Name was NULL in GDALDatasetCreateLayer");
5834 0 : return nullptr;
5835 : }
5836 :
5837 : OGRLayerH hLayer =
5838 13202 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5839 6601 : pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5840 : const_cast<char **>(papszOptions)));
5841 :
5842 : #ifdef OGRAPISPY_ENABLED
5843 6601 : if (bOGRAPISpyEnabled)
5844 8 : OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5845 : const_cast<char **>(papszOptions), hLayer);
5846 : #endif
5847 :
5848 6601 : return hLayer;
5849 : }
5850 :
5851 : /************************************************************************/
5852 : /* GDALDatasetCreateLayerFromGeomFieldDefn() */
5853 : /************************************************************************/
5854 :
5855 : /**
5856 : \brief This function attempts to create a new layer on the dataset with the
5857 : indicated name and geometry field.
5858 :
5859 : When poGeomFieldDefn is not null, most drivers should honor
5860 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5861 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5862 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5863 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5864 : very few currently.
5865 :
5866 : Note that even if a geometry coordinate precision is set and a driver honors the
5867 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5868 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5869 : with the coordinate precision. That is they are assumed to be valid once their
5870 : coordinates are rounded to it. If it might not be the case, the user may set
5871 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5872 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5873 : the passed geometries.
5874 :
5875 : The papszOptions argument can be used to control driver specific creation
5876 : options. These options are normally documented in the format specific
5877 : documentation.
5878 :
5879 : This method is the same as the C++ method GDALDataset::CreateLayer().
5880 :
5881 : @param hDS the dataset handle
5882 : @param pszName the name for the new layer. This should ideally not
5883 : match any existing layer on the datasource.
5884 : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5885 : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5886 : for drivers supporting that interface).
5887 : @param papszOptions a StringList of name=value options. Options are driver
5888 : specific.
5889 :
5890 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5891 :
5892 : @since GDAL 3.9
5893 :
5894 : */
5895 :
5896 : OGRLayerH
5897 14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5898 : OGRGeomFieldDefnH hGeomFieldDefn,
5899 : CSLConstList papszOptions)
5900 :
5901 : {
5902 14 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5903 :
5904 14 : if (!pszName)
5905 : {
5906 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5907 : "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5908 0 : return nullptr;
5909 : }
5910 :
5911 : OGRLayerH hLayer =
5912 28 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5913 14 : pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5914 : papszOptions));
5915 14 : return hLayer;
5916 : }
5917 :
5918 : /************************************************************************/
5919 : /* GDALDatasetCopyLayer() */
5920 : /************************************************************************/
5921 :
5922 : /**
5923 : \brief Duplicate an existing layer.
5924 :
5925 : This function creates a new layer, duplicate the field definitions of the
5926 : source layer and then duplicate each features of the source layer.
5927 : The papszOptions argument
5928 : can be used to control driver specific creation options. These options are
5929 : normally documented in the format specific documentation.
5930 : The source layer may come from another dataset.
5931 :
5932 : This method is the same as the C++ method GDALDataset::CopyLayer()
5933 :
5934 :
5935 : @param hDS the dataset handle.
5936 : @param hSrcLayer source layer.
5937 : @param pszNewName the name of the layer to create.
5938 : @param papszOptions a StringList of name=value options. Options are driver
5939 : specific.
5940 :
5941 : @return a handle to the layer, or NULL if an error occurs.
5942 : */
5943 52 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5944 : const char *pszNewName,
5945 : CSLConstList papszOptions)
5946 :
5947 : {
5948 52 : VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5949 52 : VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5950 52 : VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5951 :
5952 104 : return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5953 104 : OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5954 : }
5955 :
5956 : /************************************************************************/
5957 : /* GDALDatasetExecuteSQL() */
5958 : /************************************************************************/
5959 :
5960 : /**
5961 : \brief Execute an SQL statement against the data store.
5962 :
5963 : The result of an SQL query is either NULL for statements that are in error,
5964 : or that have no results set, or an OGRLayer pointer representing a results
5965 : set from the query. Note that this OGRLayer is in addition to the layers
5966 : in the data store and must be destroyed with
5967 : ReleaseResultSet() before the dataset is closed
5968 : (destroyed).
5969 :
5970 : This method is the same as the C++ method GDALDataset::ExecuteSQL()
5971 :
5972 : For more information on the SQL dialect supported internally by OGR
5973 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5974 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5975 : to the underlying RDBMS.
5976 :
5977 : Starting with OGR 1.10, the <a
5978 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5979 : also be used.
5980 :
5981 :
5982 : @param hDS the dataset handle.
5983 : @param pszStatement the SQL statement to execute.
5984 : @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5985 :
5986 : @param pszDialect allows control of the statement dialect. If set to NULL, the
5987 : OGR SQL engine will be used, except for RDBMS drivers that will use their
5988 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
5989 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5990 :
5991 : @return an OGRLayer containing the results of the query. Deallocate with
5992 : GDALDatasetReleaseResultSet().
5993 :
5994 : */
5995 :
5996 10640 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5997 : OGRGeometryH hSpatialFilter,
5998 : const char *pszDialect)
5999 :
6000 : {
6001 10640 : VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
6002 :
6003 : OGRLayerH hLayer =
6004 21280 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
6005 10640 : pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
6006 :
6007 : #ifdef OGRAPISPY_ENABLED
6008 10640 : if (bOGRAPISpyEnabled)
6009 4 : OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
6010 : hLayer);
6011 : #endif
6012 :
6013 10640 : return hLayer;
6014 : }
6015 :
6016 : /************************************************************************/
6017 : /* GDALDatasetAbortSQL() */
6018 : /************************************************************************/
6019 :
6020 : /**
6021 : \brief Abort any SQL statement running in the data store.
6022 :
6023 : This function can be safely called from any thread (pending that the dataset
6024 : object is still alive). Driver implementations will make sure that it can be
6025 : called in a thread-safe way.
6026 :
6027 : This might not be implemented by all drivers. At time of writing, only SQLite,
6028 : GPKG and PG drivers implement it
6029 :
6030 : This method is the same as the C++ method GDALDataset::AbortSQL()
6031 :
6032 : @since GDAL 3.2.0
6033 :
6034 : @param hDS the dataset handle.
6035 :
6036 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6037 : is not supported for this datasource. .
6038 :
6039 : */
6040 :
6041 6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6042 :
6043 : {
6044 6 : VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6045 6 : return GDALDataset::FromHandle(hDS)->AbortSQL();
6046 : }
6047 :
6048 : /************************************************************************/
6049 : /* GDALDatasetGetStyleTable() */
6050 : /************************************************************************/
6051 :
6052 : /**
6053 : \brief Returns dataset style table.
6054 :
6055 : This function is the same as the C++ method GDALDataset::GetStyleTable()
6056 :
6057 :
6058 : @param hDS the dataset handle
6059 : @return handle to a style table which should not be modified or freed by the
6060 : caller.
6061 : */
6062 :
6063 6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6064 :
6065 : {
6066 6 : VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6067 :
6068 : return reinterpret_cast<OGRStyleTableH>(
6069 6 : GDALDataset::FromHandle(hDS)->GetStyleTable());
6070 : }
6071 :
6072 : /************************************************************************/
6073 : /* GDALDatasetSetStyleTableDirectly() */
6074 : /************************************************************************/
6075 :
6076 : /**
6077 : \brief Set dataset style table.
6078 :
6079 : This function operate exactly as GDALDatasetSetStyleTable() except that it
6080 : assumes ownership of the passed table.
6081 :
6082 : This function is the same as the C++ method
6083 : GDALDataset::SetStyleTableDirectly()
6084 :
6085 :
6086 : @param hDS the dataset handle
6087 : @param hStyleTable style table handle to set
6088 :
6089 : */
6090 :
6091 0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6092 : OGRStyleTableH hStyleTable)
6093 :
6094 : {
6095 0 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6096 :
6097 0 : GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6098 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6099 : }
6100 :
6101 : /************************************************************************/
6102 : /* GDALDatasetSetStyleTable() */
6103 : /************************************************************************/
6104 :
6105 : /**
6106 : \brief Set dataset style table.
6107 :
6108 : This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6109 : it assumes ownership of the passed table.
6110 :
6111 : This function is the same as the C++ method GDALDataset::SetStyleTable()
6112 :
6113 :
6114 : @param hDS the dataset handle
6115 : @param hStyleTable style table handle to set
6116 :
6117 : */
6118 :
6119 5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6120 :
6121 : {
6122 5 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6123 5 : VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6124 :
6125 5 : GDALDataset::FromHandle(hDS)->SetStyleTable(
6126 5 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6127 : }
6128 :
6129 : /************************************************************************/
6130 : /* ValidateLayerCreationOptions() */
6131 : /************************************************************************/
6132 :
6133 : //! @cond Doxygen_Suppress
6134 10009 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6135 : {
6136 : const char *pszOptionList =
6137 10009 : GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6138 10009 : if (pszOptionList == nullptr && poDriver != nullptr)
6139 : {
6140 : pszOptionList =
6141 9966 : poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6142 : }
6143 20018 : CPLString osDataset;
6144 10009 : osDataset.Printf("dataset %s", GetDescription());
6145 10009 : return GDALValidateOptions(GDALDriver::ToHandle(poDriver), pszOptionList,
6146 20018 : papszLCO, "layer creation option", osDataset);
6147 : }
6148 :
6149 : //! @endcond
6150 :
6151 : /************************************************************************/
6152 : /* Release() */
6153 : /************************************************************************/
6154 :
6155 : /**
6156 : \brief Drop a reference to this dataset, and if the reference count drops to one
6157 : close (destroy) the dataset.
6158 :
6159 : This method is the same as the C function OGRReleaseDataSource().
6160 :
6161 : @deprecated. Use GDALClose() instead
6162 :
6163 : @return OGRERR_NONE on success or an error code.
6164 : */
6165 :
6166 4639 : OGRErr GDALDataset::Release()
6167 :
6168 : {
6169 4639 : ReleaseRef();
6170 4639 : return OGRERR_NONE;
6171 : }
6172 :
6173 : /************************************************************************/
6174 : /* GetRefCount() */
6175 : /************************************************************************/
6176 :
6177 : /**
6178 : \brief Fetch reference count.
6179 :
6180 : This method is the same as the C function OGR_DS_GetRefCount().
6181 :
6182 : @return the current reference count for the datasource object itself.
6183 : */
6184 :
6185 5512 : int GDALDataset::GetRefCount() const
6186 : {
6187 5512 : return nRefCount;
6188 : }
6189 :
6190 : /************************************************************************/
6191 : /* GetSummaryRefCount() */
6192 : /************************************************************************/
6193 :
6194 : /**
6195 : \brief Fetch reference count of datasource and all owned layers.
6196 :
6197 : This method is the same as the C function OGR_DS_GetSummaryRefCount().
6198 :
6199 : @deprecated
6200 :
6201 : @return the current summary reference count for the datasource and its layers.
6202 : */
6203 :
6204 0 : int GDALDataset::GetSummaryRefCount() const
6205 :
6206 : {
6207 0 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6208 0 : int nSummaryCount = nRefCount;
6209 0 : GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6210 :
6211 0 : for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6212 0 : nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6213 :
6214 0 : return nSummaryCount;
6215 : }
6216 :
6217 : /************************************************************************/
6218 : /* ICreateLayer() */
6219 : /************************************************************************/
6220 :
6221 : /**
6222 : \brief This method attempts to create a new layer on the dataset with the
6223 : indicated name, coordinate system, geometry type.
6224 :
6225 : This method is reserved to implementation by drivers.
6226 :
6227 : The papszOptions argument can be used to control driver specific creation
6228 : options. These options are normally documented in the format specific
6229 : documentation.
6230 :
6231 : @param pszName the name for the new layer. This should ideally not
6232 : match any existing layer on the datasource.
6233 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
6234 : or NULL if there is no geometry field.
6235 : @param papszOptions a StringList of name=value options. Options are driver
6236 : specific.
6237 :
6238 : @return NULL is returned on failure, or a new OGRLayer handle on success.
6239 :
6240 : */
6241 :
6242 : OGRLayer *
6243 16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6244 : CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6245 : CPL_UNUSED CSLConstList papszOptions)
6246 :
6247 : {
6248 16 : CPLError(CE_Failure, CPLE_NotSupported,
6249 : "CreateLayer() not supported by this dataset.");
6250 :
6251 16 : return nullptr;
6252 : }
6253 :
6254 : /************************************************************************/
6255 : /* CopyLayer() */
6256 : /************************************************************************/
6257 :
6258 : /**
6259 : \brief Duplicate an existing layer.
6260 :
6261 : This method creates a new layer, duplicate the field definitions of the
6262 : source layer and then duplicate each features of the source layer.
6263 : The papszOptions argument
6264 : can be used to control driver specific creation options. These options are
6265 : normally documented in the format specific documentation.
6266 : The source layer may come from another dataset.
6267 :
6268 : This method is the same as the C function GDALDatasetCopyLayer() and the
6269 : deprecated OGR_DS_CopyLayer().
6270 :
6271 : @param poSrcLayer source layer.
6272 : @param pszNewName the name of the layer to create.
6273 : @param papszOptions a StringList of name=value options. Options are driver
6274 : specific. There is a common option to set output layer
6275 : spatial reference: DST_SRSWKT. The option should be in
6276 : WKT format. Starting with GDAL 3.7, the common option
6277 : COPY_MD can be set to NO to prevent the default copying
6278 : of the metadata from the source layer to the target layer.
6279 :
6280 : @return a handle to the layer, or NULL if an error occurs.
6281 : */
6282 :
6283 168 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6284 : CSLConstList papszOptions)
6285 :
6286 : {
6287 : /* -------------------------------------------------------------------- */
6288 : /* Create the layer. */
6289 : /* -------------------------------------------------------------------- */
6290 168 : if (!TestCapability(ODsCCreateLayer))
6291 : {
6292 0 : CPLError(CE_Failure, CPLE_NotSupported,
6293 : "This datasource does not support creation of layers.");
6294 0 : return nullptr;
6295 : }
6296 :
6297 168 : const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6298 336 : OGRSpatialReference oDstSpaRef(pszSRSWKT);
6299 168 : oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6300 168 : OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6301 168 : OGRLayer *poDstLayer = nullptr;
6302 :
6303 336 : CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6304 168 : aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6305 168 : aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6306 :
6307 168 : CPLErrorReset();
6308 168 : const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6309 168 : if (nSrcGeomFieldCount == 1)
6310 : {
6311 116 : OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6312 116 : if (pszSRSWKT)
6313 5 : oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6314 116 : poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6315 116 : aosCleanedUpOptions.List());
6316 : }
6317 : else
6318 : {
6319 : poDstLayer =
6320 52 : ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6321 : }
6322 :
6323 168 : if (poDstLayer == nullptr)
6324 0 : return nullptr;
6325 :
6326 168 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6327 : {
6328 167 : CSLConstList papszMD = poSrcLayer->GetMetadata();
6329 167 : if (papszMD)
6330 33 : poDstLayer->SetMetadata(papszMD);
6331 : }
6332 :
6333 : /* -------------------------------------------------------------------- */
6334 : /* Add fields. Default to copy all fields, and make sure to */
6335 : /* establish a mapping between indices, rather than names, in */
6336 : /* case the target datasource has altered it (e.g. Shapefile */
6337 : /* limited to 10 char field names). */
6338 : /* -------------------------------------------------------------------- */
6339 168 : const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6340 :
6341 : // Initialize the index-to-index map to -1's.
6342 336 : std::vector<int> anMap(nSrcFieldCount, -1);
6343 :
6344 : // Caution: At the time of writing, the MapInfo driver
6345 : // returns NULL until a field has been added.
6346 168 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6347 168 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6348 405 : for (int iField = 0; iField < nSrcFieldCount; ++iField)
6349 : {
6350 237 : OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6351 474 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6352 :
6353 : // The field may have been already created at layer creation.
6354 237 : int iDstField = -1;
6355 237 : if (poDstFDefn)
6356 237 : iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6357 237 : if (iDstField >= 0)
6358 : {
6359 0 : anMap[iField] = iDstField;
6360 : }
6361 237 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6362 : {
6363 : // Now that we've created a field, GetLayerDefn() won't return NULL.
6364 237 : if (poDstFDefn == nullptr)
6365 0 : poDstFDefn = poDstLayer->GetLayerDefn();
6366 :
6367 : // Sanity check: if it fails, the driver is buggy.
6368 474 : if (poDstFDefn != nullptr &&
6369 237 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6370 : {
6371 0 : CPLError(CE_Warning, CPLE_AppDefined,
6372 : "The output driver has claimed to have added the %s "
6373 : "field, but it did not!",
6374 : oFieldDefn.GetNameRef());
6375 : }
6376 : else
6377 : {
6378 237 : anMap[iField] = nDstFieldCount;
6379 237 : ++nDstFieldCount;
6380 : }
6381 : }
6382 : }
6383 :
6384 : /* -------------------------------------------------------------------- */
6385 168 : std::unique_ptr<OGRCoordinateTransformation> poCT;
6386 168 : const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6387 168 : if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6388 0 : sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6389 : {
6390 0 : poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6391 0 : if (nullptr == poCT)
6392 : {
6393 0 : CPLError(CE_Failure, CPLE_NotSupported,
6394 : "This input/output spatial reference is not supported.");
6395 0 : return nullptr;
6396 : }
6397 : }
6398 : /* -------------------------------------------------------------------- */
6399 : /* Create geometry fields. */
6400 : /* -------------------------------------------------------------------- */
6401 169 : if (nSrcGeomFieldCount > 1 &&
6402 1 : TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6403 : {
6404 :
6405 3 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6406 : {
6407 2 : if (nullptr == pszSRSWKT)
6408 : {
6409 2 : poDstLayer->CreateGeomField(
6410 2 : poSrcDefn->GetGeomFieldDefn(iField));
6411 : }
6412 : else
6413 : {
6414 : OGRGeomFieldDefn *pDstGeomFieldDefn =
6415 0 : poSrcDefn->GetGeomFieldDefn(iField);
6416 0 : pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6417 0 : poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6418 : }
6419 : }
6420 : }
6421 :
6422 : /* -------------------------------------------------------------------- */
6423 : /* Check if the destination layer supports transactions and set a */
6424 : /* default number of features in a single transaction. */
6425 : /* -------------------------------------------------------------------- */
6426 : const int nGroupTransactions =
6427 168 : poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6428 :
6429 : /* -------------------------------------------------------------------- */
6430 : /* Transfer features. */
6431 : /* -------------------------------------------------------------------- */
6432 168 : poSrcLayer->ResetReading();
6433 :
6434 168 : if (nGroupTransactions <= 0)
6435 : {
6436 : while (true)
6437 : {
6438 : auto poFeature =
6439 712 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6440 :
6441 712 : if (poFeature == nullptr)
6442 159 : break;
6443 :
6444 553 : CPLErrorReset();
6445 : auto poDstFeature =
6446 553 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6447 :
6448 553 : if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6449 : OGRERR_NONE)
6450 : {
6451 0 : CPLError(CE_Failure, CPLE_AppDefined,
6452 : "Unable to translate feature " CPL_FRMT_GIB
6453 : " from layer %s.",
6454 0 : poFeature->GetFID(), poSrcDefn->GetName());
6455 0 : return poDstLayer;
6456 : }
6457 :
6458 553 : if (nullptr != poCT)
6459 : {
6460 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6461 : {
6462 0 : OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6463 0 : if (nullptr == pGeom)
6464 0 : continue;
6465 :
6466 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6467 0 : if (eErr == OGRERR_NONE)
6468 0 : continue;
6469 :
6470 0 : CPLError(CE_Failure, CPLE_AppDefined,
6471 : "Unable to transform geometry " CPL_FRMT_GIB
6472 : " from layer %s.",
6473 0 : poFeature->GetFID(), poSrcDefn->GetName());
6474 0 : return poDstLayer;
6475 : }
6476 : }
6477 :
6478 553 : poDstFeature->SetFID(poFeature->GetFID());
6479 :
6480 553 : CPLErrorReset();
6481 553 : if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6482 : {
6483 0 : return poDstLayer;
6484 : }
6485 553 : }
6486 : }
6487 : else
6488 : {
6489 9 : std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6490 : try
6491 : {
6492 9 : apoDstFeatures.resize(nGroupTransactions);
6493 : }
6494 0 : catch (const std::exception &e)
6495 : {
6496 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6497 0 : return poDstLayer;
6498 : }
6499 9 : bool bStopTransfer = false;
6500 18 : while (!bStopTransfer)
6501 : {
6502 : /* --------------------------------------------------------------------
6503 : */
6504 : /* Fill the array with features. */
6505 : /* --------------------------------------------------------------------
6506 : */
6507 : // Number of features in the temporary array.
6508 9 : int nFeatCount = 0; // Used after for.
6509 85 : for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6510 : {
6511 : auto poFeature =
6512 85 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6513 :
6514 85 : if (poFeature == nullptr)
6515 : {
6516 9 : bStopTransfer = true;
6517 9 : break;
6518 : }
6519 :
6520 76 : CPLErrorReset();
6521 76 : apoDstFeatures[nFeatCount] =
6522 152 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6523 :
6524 152 : if (apoDstFeatures[nFeatCount]->SetFrom(
6525 152 : poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6526 : {
6527 0 : CPLError(CE_Failure, CPLE_AppDefined,
6528 : "Unable to translate feature " CPL_FRMT_GIB
6529 : " from layer %s.",
6530 0 : poFeature->GetFID(), poSrcDefn->GetName());
6531 0 : bStopTransfer = true;
6532 0 : poFeature.reset();
6533 0 : break;
6534 : }
6535 :
6536 76 : if (nullptr != poCT)
6537 : {
6538 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6539 : {
6540 : OGRGeometry *pGeom =
6541 0 : apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6542 0 : if (nullptr == pGeom)
6543 0 : continue;
6544 :
6545 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6546 0 : if (eErr == OGRERR_NONE)
6547 0 : continue;
6548 :
6549 0 : CPLError(CE_Failure, CPLE_AppDefined,
6550 : "Unable to transform geometry " CPL_FRMT_GIB
6551 : " from layer %s.",
6552 0 : poFeature->GetFID(), poSrcDefn->GetName());
6553 0 : bStopTransfer = true;
6554 0 : poFeature.reset();
6555 0 : break;
6556 : }
6557 : }
6558 :
6559 76 : if (poFeature)
6560 : {
6561 76 : apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6562 : }
6563 : }
6564 :
6565 9 : CPLErrorReset();
6566 9 : bool bStopTransaction = false;
6567 18 : while (!bStopTransaction)
6568 : {
6569 9 : bStopTransaction = true;
6570 9 : if (poDstLayer->StartTransaction() != OGRERR_NONE)
6571 0 : break;
6572 85 : for (int i = 0; i < nFeatCount; ++i)
6573 : {
6574 76 : if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6575 : OGRERR_NONE)
6576 : {
6577 0 : bStopTransfer = true;
6578 0 : bStopTransaction = false;
6579 0 : break;
6580 : }
6581 76 : apoDstFeatures[i].reset();
6582 : }
6583 9 : if (bStopTransaction)
6584 : {
6585 9 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6586 0 : break;
6587 : }
6588 : else
6589 : {
6590 0 : poDstLayer->RollbackTransaction();
6591 : }
6592 : }
6593 : }
6594 : }
6595 :
6596 168 : return poDstLayer;
6597 : }
6598 :
6599 : /************************************************************************/
6600 : /* DeleteLayer() */
6601 : /************************************************************************/
6602 :
6603 : /**
6604 : \fn GDALDataset::DeleteLayer(int)
6605 : \brief Delete the indicated layer from the datasource.
6606 :
6607 : If this method is supported
6608 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6609 :
6610 : This method is the same as the C function GDALDatasetDeleteLayer() and the
6611 : deprecated OGR_DS_DeleteLayer().
6612 :
6613 : @param iLayer the index of the layer to delete.
6614 :
6615 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6616 : layers is not supported for this datasource.
6617 :
6618 : */
6619 :
6620 389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6621 :
6622 : {
6623 389 : CPLError(CE_Failure, CPLE_NotSupported,
6624 : "DeleteLayer() not supported by this dataset.");
6625 :
6626 389 : return OGRERR_UNSUPPORTED_OPERATION;
6627 : }
6628 :
6629 : /************************************************************************/
6630 : /* GetLayerByName() */
6631 : /************************************************************************/
6632 :
6633 : /**
6634 : \brief Fetch a layer by name.
6635 :
6636 : The returned layer remains owned by the
6637 : GDALDataset and should not be deleted by the application.
6638 :
6639 : This method is the same as the C function GDALDatasetGetLayerByName() and the
6640 : deprecated OGR_DS_GetLayerByName().
6641 :
6642 : @param pszName the layer name of the layer to fetch.
6643 :
6644 : @return the layer, or NULL if Layer is not found or an error occurs.
6645 : */
6646 :
6647 32090 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6648 :
6649 : {
6650 64180 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6651 :
6652 32090 : if (!pszName)
6653 5 : return nullptr;
6654 :
6655 : // First a case sensitive check.
6656 939043 : for (auto *poLayer : GetLayers())
6657 : {
6658 920647 : if (strcmp(pszName, poLayer->GetName()) == 0)
6659 13689 : return poLayer;
6660 : }
6661 :
6662 : // Then case insensitive.
6663 894270 : for (auto *poLayer : GetLayers())
6664 : {
6665 876098 : if (EQUAL(pszName, poLayer->GetName()))
6666 224 : return poLayer;
6667 : }
6668 :
6669 18172 : return nullptr;
6670 : }
6671 :
6672 : //! @cond Doxygen_Suppress
6673 : /************************************************************************/
6674 : /* ProcessSQLCreateIndex() */
6675 : /* */
6676 : /* The correct syntax for creating an index in our dialect of */
6677 : /* SQL is: */
6678 : /* */
6679 : /* CREATE INDEX ON <layername> USING <columnname> */
6680 : /************************************************************************/
6681 :
6682 28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6683 :
6684 : {
6685 28 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6686 :
6687 : /* -------------------------------------------------------------------- */
6688 : /* Do some general syntax checking. */
6689 : /* -------------------------------------------------------------------- */
6690 56 : if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6691 84 : !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6692 28 : !EQUAL(papszTokens[4], "USING"))
6693 : {
6694 0 : CSLDestroy(papszTokens);
6695 0 : CPLError(CE_Failure, CPLE_AppDefined,
6696 : "Syntax error in CREATE INDEX command.\n"
6697 : "Was '%s'\n"
6698 : "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6699 : pszSQLCommand);
6700 0 : return OGRERR_FAILURE;
6701 : }
6702 :
6703 : /* -------------------------------------------------------------------- */
6704 : /* Find the named layer. */
6705 : /* -------------------------------------------------------------------- */
6706 28 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6707 28 : if (poLayer == nullptr)
6708 : {
6709 0 : CPLError(CE_Failure, CPLE_AppDefined,
6710 : "CREATE INDEX ON failed, no such layer as `%s'.",
6711 0 : papszTokens[3]);
6712 0 : CSLDestroy(papszTokens);
6713 0 : return OGRERR_FAILURE;
6714 : }
6715 :
6716 : /* -------------------------------------------------------------------- */
6717 : /* Does this layer even support attribute indexes? */
6718 : /* -------------------------------------------------------------------- */
6719 28 : if (poLayer->GetIndex() == nullptr)
6720 : {
6721 0 : CPLError(CE_Failure, CPLE_AppDefined,
6722 : "CREATE INDEX ON not supported by this driver.");
6723 0 : CSLDestroy(papszTokens);
6724 0 : return OGRERR_FAILURE;
6725 : }
6726 :
6727 : /* -------------------------------------------------------------------- */
6728 : /* Find the named field. */
6729 : /* -------------------------------------------------------------------- */
6730 28 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6731 :
6732 28 : CSLDestroy(papszTokens);
6733 :
6734 28 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6735 : {
6736 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6737 : pszSQLCommand);
6738 0 : return OGRERR_FAILURE;
6739 : }
6740 :
6741 : /* -------------------------------------------------------------------- */
6742 : /* Attempt to create the index. */
6743 : /* -------------------------------------------------------------------- */
6744 28 : OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6745 28 : if (eErr == OGRERR_NONE)
6746 : {
6747 28 : eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6748 : }
6749 : else
6750 : {
6751 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
6752 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6753 : }
6754 :
6755 28 : return eErr;
6756 : }
6757 :
6758 : /************************************************************************/
6759 : /* ProcessSQLDropIndex() */
6760 : /* */
6761 : /* The correct syntax for dropping one or more indexes in */
6762 : /* the OGR SQL dialect is: */
6763 : /* */
6764 : /* DROP INDEX ON <layername> [USING <columnname>] */
6765 : /************************************************************************/
6766 :
6767 10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6768 :
6769 : {
6770 10 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6771 :
6772 : /* -------------------------------------------------------------------- */
6773 : /* Do some general syntax checking. */
6774 : /* -------------------------------------------------------------------- */
6775 20 : if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6776 10 : !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6777 30 : !EQUAL(papszTokens[2], "ON") ||
6778 10 : (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6779 : {
6780 0 : CSLDestroy(papszTokens);
6781 0 : CPLError(CE_Failure, CPLE_AppDefined,
6782 : "Syntax error in DROP INDEX command.\n"
6783 : "Was '%s'\n"
6784 : "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6785 : pszSQLCommand);
6786 0 : return OGRERR_FAILURE;
6787 : }
6788 :
6789 : /* -------------------------------------------------------------------- */
6790 : /* Find the named layer. */
6791 : /* -------------------------------------------------------------------- */
6792 10 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6793 10 : if (poLayer == nullptr)
6794 : {
6795 0 : CPLError(CE_Failure, CPLE_AppDefined,
6796 : "DROP INDEX ON failed, no such layer as `%s'.",
6797 0 : papszTokens[3]);
6798 0 : CSLDestroy(papszTokens);
6799 0 : return OGRERR_FAILURE;
6800 : }
6801 :
6802 : /* -------------------------------------------------------------------- */
6803 : /* Does this layer even support attribute indexes? */
6804 : /* -------------------------------------------------------------------- */
6805 10 : if (poLayer->GetIndex() == nullptr)
6806 : {
6807 0 : CPLError(CE_Failure, CPLE_AppDefined,
6808 : "Indexes not supported by this driver.");
6809 0 : CSLDestroy(papszTokens);
6810 0 : return OGRERR_FAILURE;
6811 : }
6812 :
6813 : /* -------------------------------------------------------------------- */
6814 : /* If we were not given a field name, drop all indexes. */
6815 : /* -------------------------------------------------------------------- */
6816 10 : if (CSLCount(papszTokens) == 4)
6817 : {
6818 0 : for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6819 : {
6820 : OGRAttrIndex *poAttrIndex;
6821 :
6822 0 : poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6823 0 : if (poAttrIndex != nullptr)
6824 : {
6825 0 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6826 0 : if (eErr != OGRERR_NONE)
6827 : {
6828 0 : CSLDestroy(papszTokens);
6829 0 : return eErr;
6830 : }
6831 : }
6832 : }
6833 :
6834 0 : CSLDestroy(papszTokens);
6835 0 : return OGRERR_NONE;
6836 : }
6837 :
6838 : /* -------------------------------------------------------------------- */
6839 : /* Find the named field. */
6840 : /* -------------------------------------------------------------------- */
6841 10 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6842 10 : CSLDestroy(papszTokens);
6843 :
6844 10 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6845 : {
6846 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6847 : pszSQLCommand);
6848 0 : return OGRERR_FAILURE;
6849 : }
6850 :
6851 : /* -------------------------------------------------------------------- */
6852 : /* Attempt to drop the index. */
6853 : /* -------------------------------------------------------------------- */
6854 10 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6855 :
6856 10 : return eErr;
6857 : }
6858 :
6859 : /************************************************************************/
6860 : /* ProcessSQLDropTable() */
6861 : /* */
6862 : /* The correct syntax for dropping a table (layer) in the OGR SQL */
6863 : /* dialect is: */
6864 : /* */
6865 : /* DROP TABLE <layername> */
6866 : /************************************************************************/
6867 :
6868 500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6869 :
6870 : {
6871 500 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6872 :
6873 : /* -------------------------------------------------------------------- */
6874 : /* Do some general syntax checking. */
6875 : /* -------------------------------------------------------------------- */
6876 1000 : if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6877 500 : !EQUAL(papszTokens[1], "TABLE"))
6878 : {
6879 0 : CSLDestroy(papszTokens);
6880 0 : CPLError(CE_Failure, CPLE_AppDefined,
6881 : "Syntax error in DROP TABLE command.\n"
6882 : "Was '%s'\n"
6883 : "Should be of form 'DROP TABLE <table>'",
6884 : pszSQLCommand);
6885 0 : return OGRERR_FAILURE;
6886 : }
6887 :
6888 : /* -------------------------------------------------------------------- */
6889 : /* Find the named layer. */
6890 : /* -------------------------------------------------------------------- */
6891 500 : OGRLayer *poLayer = nullptr;
6892 :
6893 500 : int i = 0; // Used after for.
6894 40199 : for (; i < GetLayerCount(); ++i)
6895 : {
6896 40199 : poLayer = GetLayer(i);
6897 :
6898 40199 : if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6899 500 : break;
6900 39699 : poLayer = nullptr;
6901 : }
6902 :
6903 500 : if (poLayer == nullptr)
6904 : {
6905 0 : CPLError(CE_Failure, CPLE_AppDefined,
6906 0 : "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6907 0 : CSLDestroy(papszTokens);
6908 0 : return OGRERR_FAILURE;
6909 : }
6910 :
6911 500 : CSLDestroy(papszTokens);
6912 :
6913 : /* -------------------------------------------------------------------- */
6914 : /* Delete it. */
6915 : /* -------------------------------------------------------------------- */
6916 :
6917 500 : return DeleteLayer(i);
6918 : }
6919 :
6920 : //! @endcond
6921 :
6922 : /************************************************************************/
6923 : /* GDALDatasetParseSQLType() */
6924 : /************************************************************************/
6925 :
6926 : /* All arguments will be altered */
6927 6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6928 : int &nPrecision)
6929 : {
6930 6 : char *pszParenthesis = strchr(pszType, '(');
6931 6 : if (pszParenthesis)
6932 : {
6933 4 : nWidth = atoi(pszParenthesis + 1);
6934 4 : *pszParenthesis = '\0';
6935 4 : char *pszComma = strchr(pszParenthesis + 1, ',');
6936 4 : if (pszComma)
6937 2 : nPrecision = atoi(pszComma + 1);
6938 : }
6939 :
6940 6 : OGRFieldType eType = OFTString;
6941 6 : if (EQUAL(pszType, "INTEGER"))
6942 0 : eType = OFTInteger;
6943 6 : else if (EQUAL(pszType, "INTEGER[]"))
6944 0 : eType = OFTIntegerList;
6945 6 : else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6946 4 : EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6947 4 : EQUAL(pszType, "REAL") /* unofficial alias */)
6948 2 : eType = OFTReal;
6949 4 : else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6950 4 : EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6951 4 : EQUAL(pszType, "REAL[]") /* unofficial alias */)
6952 0 : eType = OFTRealList;
6953 4 : else if (EQUAL(pszType, "CHARACTER") ||
6954 0 : EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6955 0 : EQUAL(pszType, "STRING") /* unofficial alias */ ||
6956 0 : EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6957 4 : eType = OFTString;
6958 0 : else if (EQUAL(pszType, "TEXT[]") ||
6959 0 : EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6960 0 : EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6961 0 : eType = OFTStringList;
6962 0 : else if (EQUAL(pszType, "DATE"))
6963 0 : eType = OFTDate;
6964 0 : else if (EQUAL(pszType, "TIME"))
6965 0 : eType = OFTTime;
6966 0 : else if (EQUAL(pszType, "TIMESTAMP") ||
6967 0 : EQUAL(pszType, "DATETIME") /* unofficial alias */)
6968 0 : eType = OFTDateTime;
6969 : else
6970 0 : CPLError(CE_Warning, CPLE_NotSupported,
6971 : "Unsupported column type '%s'. Defaulting to VARCHAR",
6972 : pszType);
6973 :
6974 6 : return eType;
6975 : }
6976 :
6977 : /************************************************************************/
6978 : /* ProcessSQLAlterTableAddColumn() */
6979 : /* */
6980 : /* The correct syntax for adding a column in the OGR SQL */
6981 : /* dialect is: */
6982 : /* */
6983 : /* ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6984 : /************************************************************************/
6985 :
6986 : //! @cond Doxygen_Suppress
6987 2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6988 :
6989 : {
6990 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6991 :
6992 : /* -------------------------------------------------------------------- */
6993 : /* Do some general syntax checking. */
6994 : /* -------------------------------------------------------------------- */
6995 2 : const char *pszLayerName = nullptr;
6996 2 : const char *pszColumnName = nullptr;
6997 2 : int iTypeIndex = 0;
6998 2 : const int nTokens = CSLCount(papszTokens);
6999 :
7000 2 : if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7001 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
7002 2 : EQUAL(papszTokens[4], "COLUMN"))
7003 : {
7004 1 : pszLayerName = papszTokens[2];
7005 1 : pszColumnName = papszTokens[5];
7006 1 : iTypeIndex = 6;
7007 : }
7008 1 : else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
7009 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
7010 : {
7011 1 : pszLayerName = papszTokens[2];
7012 1 : pszColumnName = papszTokens[4];
7013 1 : iTypeIndex = 5;
7014 : }
7015 : else
7016 : {
7017 0 : CSLDestroy(papszTokens);
7018 0 : CPLError(CE_Failure, CPLE_AppDefined,
7019 : "Syntax error in ALTER TABLE ADD COLUMN command.\n"
7020 : "Was '%s'\n"
7021 : "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
7022 : "<columnname> <columntype>'",
7023 : pszSQLCommand);
7024 0 : return OGRERR_FAILURE;
7025 : }
7026 :
7027 : /* -------------------------------------------------------------------- */
7028 : /* Merge type components into a single string if there were split */
7029 : /* with spaces */
7030 : /* -------------------------------------------------------------------- */
7031 4 : CPLString osType;
7032 6 : for (int i = iTypeIndex; i < nTokens; ++i)
7033 : {
7034 4 : osType += papszTokens[i];
7035 4 : CPLFree(papszTokens[i]);
7036 : }
7037 2 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7038 2 : papszTokens[iTypeIndex + 1] = nullptr;
7039 :
7040 : /* -------------------------------------------------------------------- */
7041 : /* Find the named layer. */
7042 : /* -------------------------------------------------------------------- */
7043 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7044 2 : if (poLayer == nullptr)
7045 : {
7046 0 : CPLError(CE_Failure, CPLE_AppDefined,
7047 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7048 : pszLayerName);
7049 0 : CSLDestroy(papszTokens);
7050 0 : return OGRERR_FAILURE;
7051 : }
7052 :
7053 : /* -------------------------------------------------------------------- */
7054 : /* Add column. */
7055 : /* -------------------------------------------------------------------- */
7056 :
7057 2 : int nWidth = 0;
7058 2 : int nPrecision = 0;
7059 2 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7060 4 : OGRFieldDefn oFieldDefn(pszColumnName, eType);
7061 2 : oFieldDefn.SetWidth(nWidth);
7062 2 : oFieldDefn.SetPrecision(nPrecision);
7063 :
7064 2 : CSLDestroy(papszTokens);
7065 :
7066 2 : return poLayer->CreateField(&oFieldDefn);
7067 : }
7068 :
7069 : /************************************************************************/
7070 : /* ProcessSQLAlterTableDropColumn() */
7071 : /* */
7072 : /* The correct syntax for dropping a column in the OGR SQL */
7073 : /* dialect is: */
7074 : /* */
7075 : /* ALTER TABLE <layername> DROP [COLUMN] <columnname> */
7076 : /************************************************************************/
7077 :
7078 2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7079 :
7080 : {
7081 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7082 :
7083 : /* -------------------------------------------------------------------- */
7084 : /* Do some general syntax checking. */
7085 : /* -------------------------------------------------------------------- */
7086 2 : const char *pszLayerName = nullptr;
7087 2 : const char *pszColumnName = nullptr;
7088 3 : if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7089 4 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7090 1 : EQUAL(papszTokens[4], "COLUMN"))
7091 : {
7092 1 : pszLayerName = papszTokens[2];
7093 1 : pszColumnName = papszTokens[5];
7094 : }
7095 2 : else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7096 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7097 : {
7098 1 : pszLayerName = papszTokens[2];
7099 1 : pszColumnName = papszTokens[4];
7100 : }
7101 : else
7102 : {
7103 0 : CSLDestroy(papszTokens);
7104 0 : CPLError(CE_Failure, CPLE_AppDefined,
7105 : "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7106 : "Was '%s'\n"
7107 : "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7108 : "<columnname>'",
7109 : pszSQLCommand);
7110 0 : return OGRERR_FAILURE;
7111 : }
7112 :
7113 : /* -------------------------------------------------------------------- */
7114 : /* Find the named layer. */
7115 : /* -------------------------------------------------------------------- */
7116 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7117 2 : if (poLayer == nullptr)
7118 : {
7119 0 : CPLError(CE_Failure, CPLE_AppDefined,
7120 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7121 : pszLayerName);
7122 0 : CSLDestroy(papszTokens);
7123 0 : return OGRERR_FAILURE;
7124 : }
7125 :
7126 : /* -------------------------------------------------------------------- */
7127 : /* Find the field. */
7128 : /* -------------------------------------------------------------------- */
7129 :
7130 2 : int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7131 2 : if (nFieldIndex < 0)
7132 : {
7133 0 : CPLError(CE_Failure, CPLE_AppDefined,
7134 : "%s failed, no such field as `%s'.", pszSQLCommand,
7135 : pszColumnName);
7136 0 : CSLDestroy(papszTokens);
7137 0 : return OGRERR_FAILURE;
7138 : }
7139 :
7140 : /* -------------------------------------------------------------------- */
7141 : /* Remove it. */
7142 : /* -------------------------------------------------------------------- */
7143 :
7144 2 : CSLDestroy(papszTokens);
7145 :
7146 2 : return poLayer->DeleteField(nFieldIndex);
7147 : }
7148 :
7149 : /************************************************************************/
7150 : /* ProcessSQLAlterTableRenameColumn() */
7151 : /* */
7152 : /* The correct syntax for renaming a column in the OGR SQL */
7153 : /* dialect is: */
7154 : /* */
7155 : /* ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7156 : /************************************************************************/
7157 :
7158 2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7159 :
7160 : {
7161 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7162 :
7163 : /* -------------------------------------------------------------------- */
7164 : /* Do some general syntax checking. */
7165 : /* -------------------------------------------------------------------- */
7166 2 : const char *pszLayerName = nullptr;
7167 2 : const char *pszOldColName = nullptr;
7168 2 : const char *pszNewColName = nullptr;
7169 3 : if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7170 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7171 3 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7172 : {
7173 1 : pszLayerName = papszTokens[2];
7174 1 : pszOldColName = papszTokens[5];
7175 1 : pszNewColName = papszTokens[7];
7176 : }
7177 2 : else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7178 1 : EQUAL(papszTokens[1], "TABLE") &&
7179 2 : EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7180 : {
7181 1 : pszLayerName = papszTokens[2];
7182 1 : pszOldColName = papszTokens[4];
7183 1 : pszNewColName = papszTokens[6];
7184 : }
7185 : else
7186 : {
7187 0 : CSLDestroy(papszTokens);
7188 0 : CPLError(CE_Failure, CPLE_AppDefined,
7189 : "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7190 : "Was '%s'\n"
7191 : "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7192 : "<columnname> TO <newname>'",
7193 : pszSQLCommand);
7194 0 : return OGRERR_FAILURE;
7195 : }
7196 :
7197 : /* -------------------------------------------------------------------- */
7198 : /* Find the named layer. */
7199 : /* -------------------------------------------------------------------- */
7200 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7201 2 : if (poLayer == nullptr)
7202 : {
7203 0 : CPLError(CE_Failure, CPLE_AppDefined,
7204 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7205 : pszLayerName);
7206 0 : CSLDestroy(papszTokens);
7207 0 : return OGRERR_FAILURE;
7208 : }
7209 :
7210 : /* -------------------------------------------------------------------- */
7211 : /* Find the field. */
7212 : /* -------------------------------------------------------------------- */
7213 :
7214 : const int nFieldIndex =
7215 2 : poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7216 2 : if (nFieldIndex < 0)
7217 : {
7218 0 : CPLError(CE_Failure, CPLE_AppDefined,
7219 : "%s failed, no such field as `%s'.", pszSQLCommand,
7220 : pszOldColName);
7221 0 : CSLDestroy(papszTokens);
7222 0 : return OGRERR_FAILURE;
7223 : }
7224 :
7225 : /* -------------------------------------------------------------------- */
7226 : /* Rename column. */
7227 : /* -------------------------------------------------------------------- */
7228 : OGRFieldDefn *poOldFieldDefn =
7229 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7230 4 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7231 2 : oNewFieldDefn.SetName(pszNewColName);
7232 :
7233 2 : CSLDestroy(papszTokens);
7234 :
7235 2 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7236 2 : ALTER_NAME_FLAG);
7237 : }
7238 :
7239 : /************************************************************************/
7240 : /* ProcessSQLAlterTableAlterColumn() */
7241 : /* */
7242 : /* The correct syntax for altering the type of a column in the */
7243 : /* OGR SQL dialect is: */
7244 : /* */
7245 : /* ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7246 : /************************************************************************/
7247 :
7248 4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7249 :
7250 : {
7251 4 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7252 :
7253 : /* -------------------------------------------------------------------- */
7254 : /* Do some general syntax checking. */
7255 : /* -------------------------------------------------------------------- */
7256 4 : const char *pszLayerName = nullptr;
7257 4 : const char *pszColumnName = nullptr;
7258 4 : int iTypeIndex = 0;
7259 4 : const int nTokens = CSLCount(papszTokens);
7260 :
7261 4 : if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7262 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7263 2 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7264 : {
7265 2 : pszLayerName = papszTokens[2];
7266 2 : pszColumnName = papszTokens[5];
7267 2 : iTypeIndex = 7;
7268 : }
7269 2 : else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7270 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7271 2 : EQUAL(papszTokens[5], "TYPE"))
7272 : {
7273 2 : pszLayerName = papszTokens[2];
7274 2 : pszColumnName = papszTokens[4];
7275 2 : iTypeIndex = 6;
7276 : }
7277 : else
7278 : {
7279 0 : CSLDestroy(papszTokens);
7280 0 : CPLError(CE_Failure, CPLE_AppDefined,
7281 : "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7282 : "Was '%s'\n"
7283 : "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7284 : "<columnname> TYPE <columntype>'",
7285 : pszSQLCommand);
7286 0 : return OGRERR_FAILURE;
7287 : }
7288 :
7289 : /* -------------------------------------------------------------------- */
7290 : /* Merge type components into a single string if there were split */
7291 : /* with spaces */
7292 : /* -------------------------------------------------------------------- */
7293 8 : CPLString osType;
7294 8 : for (int i = iTypeIndex; i < nTokens; ++i)
7295 : {
7296 4 : osType += papszTokens[i];
7297 4 : CPLFree(papszTokens[i]);
7298 : }
7299 4 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7300 4 : papszTokens[iTypeIndex + 1] = nullptr;
7301 :
7302 : /* -------------------------------------------------------------------- */
7303 : /* Find the named layer. */
7304 : /* -------------------------------------------------------------------- */
7305 4 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7306 4 : if (poLayer == nullptr)
7307 : {
7308 0 : CPLError(CE_Failure, CPLE_AppDefined,
7309 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7310 : pszLayerName);
7311 0 : CSLDestroy(papszTokens);
7312 0 : return OGRERR_FAILURE;
7313 : }
7314 :
7315 : /* -------------------------------------------------------------------- */
7316 : /* Find the field. */
7317 : /* -------------------------------------------------------------------- */
7318 :
7319 : const int nFieldIndex =
7320 4 : poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7321 4 : if (nFieldIndex < 0)
7322 : {
7323 0 : CPLError(CE_Failure, CPLE_AppDefined,
7324 : "%s failed, no such field as `%s'.", pszSQLCommand,
7325 : pszColumnName);
7326 0 : CSLDestroy(papszTokens);
7327 0 : return OGRERR_FAILURE;
7328 : }
7329 :
7330 : /* -------------------------------------------------------------------- */
7331 : /* Alter column. */
7332 : /* -------------------------------------------------------------------- */
7333 :
7334 : OGRFieldDefn *poOldFieldDefn =
7335 4 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7336 8 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7337 :
7338 4 : int nWidth = 0;
7339 4 : int nPrecision = 0;
7340 4 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7341 4 : oNewFieldDefn.SetType(eType);
7342 4 : oNewFieldDefn.SetWidth(nWidth);
7343 4 : oNewFieldDefn.SetPrecision(nPrecision);
7344 :
7345 4 : int l_nFlags = 0;
7346 4 : if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7347 2 : l_nFlags |= ALTER_TYPE_FLAG;
7348 4 : if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7349 0 : poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7350 4 : l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7351 :
7352 4 : CSLDestroy(papszTokens);
7353 :
7354 4 : if (l_nFlags == 0)
7355 0 : return OGRERR_NONE;
7356 :
7357 4 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7358 : }
7359 :
7360 : //! @endcond
7361 :
7362 : /************************************************************************/
7363 : /* ExecuteSQL() */
7364 : /************************************************************************/
7365 :
7366 : /**
7367 : \brief Execute an SQL statement against the data store.
7368 :
7369 : The result of an SQL query is either NULL for statements that are in error,
7370 : or that have no results set, or an OGRLayer pointer representing a results
7371 : set from the query. Note that this OGRLayer is in addition to the layers
7372 : in the data store and must be destroyed with
7373 : ReleaseResultSet() before the dataset is closed
7374 : (destroyed).
7375 :
7376 : This method is the same as the C function GDALDatasetExecuteSQL() and the
7377 : deprecated OGR_DS_ExecuteSQL().
7378 :
7379 : For more information on the SQL dialect supported internally by OGR
7380 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7381 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7382 : to the underlying RDBMS.
7383 :
7384 : Starting with OGR 1.10, the <a
7385 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7386 : also be used.
7387 :
7388 : @param pszStatement the SQL statement to execute.
7389 : @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7390 : @param pszDialect allows control of the statement dialect. If set to NULL, the
7391 : OGR SQL engine will be used, except for RDBMS drivers that will use their
7392 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
7393 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7394 :
7395 : @return an OGRLayer containing the results of the query. Deallocate with
7396 : ReleaseResultSet().
7397 :
7398 : */
7399 :
7400 4040 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7401 : OGRGeometry *poSpatialFilter,
7402 : const char *pszDialect)
7403 :
7404 : {
7405 4040 : return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7406 : }
7407 :
7408 : //! @cond Doxygen_Suppress
7409 : OGRLayer *
7410 4048 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7411 : const char *pszDialect,
7412 : swq_select_parse_options *poSelectParseOptions)
7413 :
7414 : {
7415 4048 : if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7416 : {
7417 : #ifdef SQLITE_ENABLED
7418 668 : return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7419 668 : pszDialect);
7420 : #else
7421 : CPLError(CE_Failure, CPLE_NotSupported,
7422 : "The SQLite driver needs to be compiled to support the "
7423 : "SQLite SQL dialect");
7424 : return nullptr;
7425 : #endif
7426 : }
7427 :
7428 3380 : if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7429 14 : !EQUAL(pszDialect, "OGRSQL"))
7430 : {
7431 6 : std::string osDialectList = "'OGRSQL'";
7432 : #ifdef SQLITE_ENABLED
7433 3 : osDialectList += ", 'SQLITE'";
7434 : #endif
7435 : const char *pszDialects =
7436 3 : GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7437 3 : if (pszDialects)
7438 : {
7439 : const CPLStringList aosTokens(
7440 0 : CSLTokenizeString2(pszDialects, " ", 0));
7441 0 : for (int i = 0; i < aosTokens.size(); ++i)
7442 : {
7443 0 : if (!EQUAL(aosTokens[i], "OGRSQL") &&
7444 0 : !EQUAL(aosTokens[i], "SQLITE"))
7445 : {
7446 0 : osDialectList += ", '";
7447 0 : osDialectList += aosTokens[i];
7448 0 : osDialectList += "'";
7449 : }
7450 : }
7451 : }
7452 3 : CPLError(CE_Warning, CPLE_NotSupported,
7453 : "Dialect '%s' is unsupported. Only supported dialects are %s. "
7454 : "Defaulting to OGRSQL",
7455 : pszDialect, osDialectList.c_str());
7456 : }
7457 :
7458 : /* -------------------------------------------------------------------- */
7459 : /* Handle CREATE INDEX statements specially. */
7460 : /* -------------------------------------------------------------------- */
7461 3380 : if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7462 : {
7463 28 : ProcessSQLCreateIndex(pszStatement);
7464 28 : return nullptr;
7465 : }
7466 :
7467 : /* -------------------------------------------------------------------- */
7468 : /* Handle DROP INDEX statements specially. */
7469 : /* -------------------------------------------------------------------- */
7470 3352 : if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7471 : {
7472 10 : ProcessSQLDropIndex(pszStatement);
7473 10 : return nullptr;
7474 : }
7475 :
7476 : /* -------------------------------------------------------------------- */
7477 : /* Handle DROP TABLE statements specially. */
7478 : /* -------------------------------------------------------------------- */
7479 3342 : if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7480 : {
7481 500 : ProcessSQLDropTable(pszStatement);
7482 500 : return nullptr;
7483 : }
7484 :
7485 : /* -------------------------------------------------------------------- */
7486 : /* Handle ALTER TABLE statements specially. */
7487 : /* -------------------------------------------------------------------- */
7488 2842 : if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7489 : {
7490 11 : char **papszTokens = CSLTokenizeString(pszStatement);
7491 11 : const int nTokens = CSLCount(papszTokens);
7492 11 : if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7493 : {
7494 2 : ProcessSQLAlterTableAddColumn(pszStatement);
7495 2 : CSLDestroy(papszTokens);
7496 2 : return nullptr;
7497 : }
7498 9 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7499 : {
7500 2 : ProcessSQLAlterTableDropColumn(pszStatement);
7501 2 : CSLDestroy(papszTokens);
7502 2 : return nullptr;
7503 : }
7504 7 : else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7505 1 : EQUAL(papszTokens[4], "TO"))
7506 : {
7507 1 : const char *pszSrcTableName = papszTokens[2];
7508 1 : const char *pszDstTableName = papszTokens[5];
7509 1 : auto poSrcLayer = GetLayerByName(pszSrcTableName);
7510 1 : if (poSrcLayer)
7511 : {
7512 1 : CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7513 : }
7514 : else
7515 : {
7516 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7517 : }
7518 1 : CSLDestroy(papszTokens);
7519 1 : return nullptr;
7520 : }
7521 6 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7522 : {
7523 2 : ProcessSQLAlterTableRenameColumn(pszStatement);
7524 2 : CSLDestroy(papszTokens);
7525 2 : return nullptr;
7526 : }
7527 4 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7528 : {
7529 4 : ProcessSQLAlterTableAlterColumn(pszStatement);
7530 4 : CSLDestroy(papszTokens);
7531 4 : return nullptr;
7532 : }
7533 : else
7534 : {
7535 0 : CPLError(CE_Failure, CPLE_AppDefined,
7536 : "Unsupported ALTER TABLE command : %s", pszStatement);
7537 0 : CSLDestroy(papszTokens);
7538 0 : return nullptr;
7539 : }
7540 : }
7541 :
7542 : /* -------------------------------------------------------------------- */
7543 : /* Preparse the SQL statement. */
7544 : /* -------------------------------------------------------------------- */
7545 2831 : swq_select *psSelectInfo = new swq_select();
7546 2831 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7547 2831 : if (poSelectParseOptions != nullptr)
7548 8 : poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7549 2831 : if (psSelectInfo->preparse(pszStatement,
7550 2831 : poCustomFuncRegistrar != nullptr) != CE_None)
7551 : {
7552 178 : delete psSelectInfo;
7553 178 : return nullptr;
7554 : }
7555 :
7556 : /* -------------------------------------------------------------------- */
7557 : /* If there is no UNION ALL, build result layer. */
7558 : /* -------------------------------------------------------------------- */
7559 2653 : if (psSelectInfo->poOtherSelect == nullptr)
7560 : {
7561 2647 : return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7562 2647 : pszDialect, poSelectParseOptions);
7563 : }
7564 :
7565 : /* -------------------------------------------------------------------- */
7566 : /* Build result union layer. */
7567 : /* -------------------------------------------------------------------- */
7568 6 : int nSrcLayers = 0;
7569 6 : OGRLayer **papoSrcLayers = nullptr;
7570 :
7571 6 : do
7572 : {
7573 12 : swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7574 12 : psSelectInfo->poOtherSelect = nullptr;
7575 :
7576 12 : OGRLayer *poLayer = BuildLayerFromSelectInfo(
7577 : psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7578 12 : if (poLayer == nullptr)
7579 : {
7580 : // Each source layer owns an independent select info.
7581 0 : for (int i = 0; i < nSrcLayers; ++i)
7582 0 : delete papoSrcLayers[i];
7583 0 : CPLFree(papoSrcLayers);
7584 :
7585 : // So we just have to destroy the remaining select info.
7586 0 : delete psNextSelectInfo;
7587 :
7588 0 : return nullptr;
7589 : }
7590 : else
7591 : {
7592 24 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7593 12 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7594 12 : papoSrcLayers[nSrcLayers] = poLayer;
7595 12 : ++nSrcLayers;
7596 :
7597 12 : psSelectInfo = psNextSelectInfo;
7598 : }
7599 12 : } while (psSelectInfo != nullptr);
7600 :
7601 6 : return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7602 : }
7603 :
7604 : //! @endcond
7605 :
7606 : /************************************************************************/
7607 : /* AbortSQL() */
7608 : /************************************************************************/
7609 :
7610 : /**
7611 : \brief Abort any SQL statement running in the data store.
7612 :
7613 : This function can be safely called from any thread (pending that the dataset
7614 : object is still alive). Driver implementations will make sure that it can be
7615 : called in a thread-safe way.
7616 :
7617 : This might not be implemented by all drivers. At time of writing, only SQLite,
7618 : GPKG and PG drivers implement it
7619 :
7620 : This method is the same as the C method GDALDatasetAbortSQL()
7621 :
7622 : @since GDAL 3.2.0
7623 :
7624 :
7625 : */
7626 :
7627 0 : OGRErr GDALDataset::AbortSQL()
7628 : {
7629 0 : CPLError(CE_Failure, CPLE_NotSupported,
7630 : "AbortSQL is not supported for this driver.");
7631 0 : return OGRERR_UNSUPPORTED_OPERATION;
7632 : }
7633 :
7634 : /************************************************************************/
7635 : /* BuildLayerFromSelectInfo() */
7636 : /************************************************************************/
7637 :
7638 : struct GDALSQLParseInfo
7639 : {
7640 : swq_field_list sFieldList;
7641 : int nExtraDSCount;
7642 : GDALDataset **papoExtraDS;
7643 : char *pszWHERE;
7644 : };
7645 :
7646 2659 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7647 : swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7648 : const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7649 : {
7650 5318 : std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7651 :
7652 2659 : std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7653 : GDALSQLParseInfo *psParseInfo =
7654 2659 : BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7655 :
7656 2659 : if (psParseInfo)
7657 : {
7658 2624 : const auto nErrorCounter = CPLGetErrorCounter();
7659 5248 : poResults = std::make_unique<OGRGenSQLResultsLayer>(
7660 2624 : this, std::move(psSelectInfoUnique), poSpatialFilter,
7661 5248 : psParseInfo->pszWHERE, pszDialect);
7662 2720 : if (CPLGetErrorCounter() > nErrorCounter &&
7663 96 : CPLGetLastErrorType() != CE_None)
7664 96 : poResults.reset();
7665 : }
7666 :
7667 2659 : DestroyParseInfo(psParseInfo);
7668 :
7669 5318 : return poResults.release();
7670 : }
7671 :
7672 : /************************************************************************/
7673 : /* DestroyParseInfo() */
7674 : /************************************************************************/
7675 :
7676 : //! @cond Doxygen_Suppress
7677 2728 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7678 : {
7679 2728 : if (psParseInfo == nullptr)
7680 35 : return;
7681 :
7682 2693 : CPLFree(psParseInfo->sFieldList.names);
7683 2693 : CPLFree(psParseInfo->sFieldList.types);
7684 2693 : CPLFree(psParseInfo->sFieldList.table_ids);
7685 2693 : CPLFree(psParseInfo->sFieldList.ids);
7686 :
7687 : // Release the datasets we have opened with OGROpenShared()
7688 : // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7689 : // has taken a reference on them, which it will release in its
7690 : // destructor.
7691 2700 : for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7692 7 : GDALClose(psParseInfo->papoExtraDS[iEDS]);
7693 :
7694 2693 : CPLFree(psParseInfo->papoExtraDS);
7695 2693 : CPLFree(psParseInfo->pszWHERE);
7696 2693 : CPLFree(psParseInfo);
7697 : }
7698 :
7699 : /************************************************************************/
7700 : /* BuildParseInfo() */
7701 : /************************************************************************/
7702 :
7703 : GDALSQLParseInfo *
7704 2693 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7705 : swq_select_parse_options *poSelectParseOptions)
7706 : {
7707 2693 : int nFirstLayerFirstSpecialFieldIndex = 0;
7708 :
7709 : GDALSQLParseInfo *psParseInfo =
7710 2693 : static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7711 :
7712 : /* -------------------------------------------------------------------- */
7713 : /* Validate that all the source tables are recognized, count */
7714 : /* fields. */
7715 : /* -------------------------------------------------------------------- */
7716 2693 : int nFieldCount = 0;
7717 :
7718 5454 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7719 : {
7720 2764 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7721 2764 : GDALDataset *poTableDS = this;
7722 :
7723 2764 : if (psTableDef->data_source != nullptr)
7724 : {
7725 7 : poTableDS = GDALDataset::FromHandle(
7726 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7727 7 : if (poTableDS == nullptr)
7728 : {
7729 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
7730 0 : CPLError(CE_Failure, CPLE_AppDefined,
7731 : "Unable to open secondary datasource "
7732 : "`%s' required by JOIN.",
7733 : psTableDef->data_source);
7734 :
7735 0 : DestroyParseInfo(psParseInfo);
7736 0 : return nullptr;
7737 : }
7738 :
7739 : // Keep in an array to release at the end of this function.
7740 14 : psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7741 7 : psParseInfo->papoExtraDS,
7742 7 : sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7743 7 : psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7744 : }
7745 :
7746 : OGRLayer *poSrcLayer =
7747 2764 : poTableDS->GetLayerByName(psTableDef->table_name);
7748 :
7749 2764 : if (poSrcLayer == nullptr)
7750 : {
7751 3 : CPLError(CE_Failure, CPLE_AppDefined,
7752 : "SELECT from table %s failed, no such table/featureclass.",
7753 : psTableDef->table_name);
7754 :
7755 3 : DestroyParseInfo(psParseInfo);
7756 3 : return nullptr;
7757 : }
7758 :
7759 2761 : nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7760 2761 : if (iTable == 0 ||
7761 34 : (poSelectParseOptions &&
7762 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7763 2724 : nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7764 :
7765 2761 : const char *pszFID = poSrcLayer->GetFIDColumn();
7766 3372 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7767 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7768 561 : nFieldCount++;
7769 : }
7770 :
7771 : /* -------------------------------------------------------------------- */
7772 : /* Build the field list for all indicated tables. */
7773 : /* -------------------------------------------------------------------- */
7774 :
7775 2690 : psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7776 2690 : psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7777 :
7778 2690 : psParseInfo->sFieldList.count = 0;
7779 2690 : psParseInfo->sFieldList.names = static_cast<char **>(
7780 2690 : CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7781 5380 : psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7782 2690 : sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7783 2690 : psParseInfo->sFieldList.table_ids = static_cast<int *>(
7784 2690 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7785 2690 : psParseInfo->sFieldList.ids = static_cast<int *>(
7786 2690 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7787 :
7788 2690 : bool bIsFID64 = false;
7789 5451 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7790 : {
7791 2761 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7792 2761 : GDALDataset *poTableDS = this;
7793 :
7794 2761 : if (psTableDef->data_source != nullptr)
7795 : {
7796 7 : poTableDS = GDALDataset::FromHandle(
7797 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7798 7 : CPLAssert(poTableDS != nullptr);
7799 7 : poTableDS->Dereference();
7800 : }
7801 :
7802 : OGRLayer *poSrcLayer =
7803 2761 : poTableDS->GetLayerByName(psTableDef->table_name);
7804 :
7805 2761 : for (int iField = 0;
7806 21144 : iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7807 : {
7808 : OGRFieldDefn *poFDefn =
7809 18383 : poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7810 18383 : const int iOutField = psParseInfo->sFieldList.count++;
7811 36766 : psParseInfo->sFieldList.names[iOutField] =
7812 18383 : const_cast<char *>(poFDefn->GetNameRef());
7813 18383 : if (poFDefn->GetType() == OFTInteger)
7814 : {
7815 5134 : if (poFDefn->GetSubType() == OFSTBoolean)
7816 160 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7817 : else
7818 4974 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7819 : }
7820 13249 : else if (poFDefn->GetType() == OFTInteger64)
7821 : {
7822 801 : if (poFDefn->GetSubType() == OFSTBoolean)
7823 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7824 : else
7825 801 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7826 : }
7827 12448 : else if (poFDefn->GetType() == OFTReal)
7828 2779 : psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7829 9669 : else if (poFDefn->GetType() == OFTString)
7830 6432 : psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7831 3237 : else if (poFDefn->GetType() == OFTTime)
7832 93 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7833 3144 : else if (poFDefn->GetType() == OFTDate)
7834 161 : psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7835 2983 : else if (poFDefn->GetType() == OFTDateTime)
7836 939 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7837 : else
7838 2044 : psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7839 :
7840 18383 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7841 18383 : psParseInfo->sFieldList.ids[iOutField] = iField;
7842 : }
7843 :
7844 2761 : if (iTable == 0)
7845 : {
7846 2690 : nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7847 : }
7848 :
7849 2761 : if (iTable == 0 ||
7850 34 : (poSelectParseOptions &&
7851 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7852 : {
7853 :
7854 2724 : for (int iField = 0;
7855 5012 : iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7856 : iField++)
7857 : {
7858 : OGRGeomFieldDefn *poFDefn =
7859 2288 : poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7860 2288 : const int iOutField = psParseInfo->sFieldList.count++;
7861 4576 : psParseInfo->sFieldList.names[iOutField] =
7862 2288 : const_cast<char *>(poFDefn->GetNameRef());
7863 2288 : if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7864 1453 : psParseInfo->sFieldList.names[iOutField] =
7865 : const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7866 2288 : psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7867 :
7868 2288 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7869 2288 : psParseInfo->sFieldList.ids[iOutField] =
7870 2288 : GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7871 : poSrcLayer->GetLayerDefn(), iField);
7872 : }
7873 : }
7874 :
7875 2762 : if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7876 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7877 : {
7878 1 : bIsFID64 = true;
7879 : }
7880 : }
7881 :
7882 : /* -------------------------------------------------------------------- */
7883 : /* Expand '*' in 'SELECT *' now before we add the pseudo fields */
7884 : /* -------------------------------------------------------------------- */
7885 2690 : const bool bAlwaysPrefixWithTableName =
7886 2732 : poSelectParseOptions &&
7887 42 : poSelectParseOptions->bAlwaysPrefixWithTableName;
7888 2690 : if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7889 2690 : bAlwaysPrefixWithTableName) != CE_None)
7890 : {
7891 2 : DestroyParseInfo(psParseInfo);
7892 2 : return nullptr;
7893 : }
7894 :
7895 16128 : for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7896 : {
7897 13440 : psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7898 13440 : const_cast<char *>(SpecialFieldNames[iField]);
7899 13440 : psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7900 13440 : (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7901 : : SpecialFieldTypes[iField];
7902 13440 : psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7903 13440 : psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7904 13440 : nFirstLayerFirstSpecialFieldIndex + iField;
7905 13440 : psParseInfo->sFieldList.count++;
7906 : }
7907 :
7908 : /* In the case a layer has an explicit FID column name, then add it */
7909 : /* so it can be selected */
7910 5447 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7911 : {
7912 2759 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7913 2759 : GDALDataset *poTableDS = this;
7914 :
7915 2759 : if (psTableDef->data_source != nullptr)
7916 : {
7917 7 : poTableDS = GDALDataset::FromHandle(
7918 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7919 7 : CPLAssert(poTableDS != nullptr);
7920 7 : poTableDS->Dereference();
7921 : }
7922 :
7923 : OGRLayer *poSrcLayer =
7924 2759 : poTableDS->GetLayerByName(psTableDef->table_name);
7925 :
7926 2759 : const char *pszFID = poSrcLayer->GetFIDColumn();
7927 3370 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7928 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7929 : {
7930 561 : const int iOutField = psParseInfo->sFieldList.count++;
7931 561 : psParseInfo->sFieldList.names[iOutField] =
7932 : const_cast<char *>(pszFID);
7933 561 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7934 0 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7935 : {
7936 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7937 : }
7938 : else
7939 : {
7940 561 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7941 : }
7942 561 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7943 1122 : psParseInfo->sFieldList.ids[iOutField] =
7944 561 : poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7945 : }
7946 : }
7947 :
7948 : /* -------------------------------------------------------------------- */
7949 : /* Finish the parse operation. */
7950 : /* -------------------------------------------------------------------- */
7951 2688 : if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7952 : CE_None)
7953 : {
7954 30 : DestroyParseInfo(psParseInfo);
7955 30 : return nullptr;
7956 : }
7957 :
7958 : /* -------------------------------------------------------------------- */
7959 : /* Extract the WHERE expression to use separately. */
7960 : /* -------------------------------------------------------------------- */
7961 2658 : if (psSelectInfo->where_expr != nullptr)
7962 : {
7963 1128 : psParseInfo->pszWHERE =
7964 1128 : psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7965 : // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7966 : }
7967 :
7968 2658 : return psParseInfo;
7969 : }
7970 :
7971 : //! @endcond
7972 :
7973 : /************************************************************************/
7974 : /* ReleaseResultSet() */
7975 : /************************************************************************/
7976 :
7977 : /**
7978 : \brief Release results of ExecuteSQL().
7979 :
7980 : This method should only be used to deallocate OGRLayers resulting from
7981 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
7982 : results set before destroying the GDALDataset may cause errors.
7983 :
7984 : This method is the same as the C function GDALDatasetReleaseResultSet() and the
7985 : deprecated OGR_DS_ReleaseResultSet().
7986 :
7987 : @param poResultsSet the result of a previous ExecuteSQL() call.
7988 : */
7989 :
7990 2570 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7991 :
7992 : {
7993 2570 : delete poResultsSet;
7994 2570 : }
7995 :
7996 : /************************************************************************/
7997 : /* GetStyleTable() */
7998 : /************************************************************************/
7999 :
8000 : /**
8001 : \brief Returns dataset style table.
8002 :
8003 : This method is the same as the C function GDALDatasetGetStyleTable() and the
8004 : deprecated OGR_DS_GetStyleTable().
8005 :
8006 : @return pointer to a style table which should not be modified or freed by the
8007 : caller.
8008 : */
8009 :
8010 1006 : OGRStyleTable *GDALDataset::GetStyleTable()
8011 : {
8012 1006 : return m_poStyleTable;
8013 : }
8014 :
8015 : /************************************************************************/
8016 : /* SetStyleTableDirectly() */
8017 : /************************************************************************/
8018 :
8019 : /**
8020 : \brief Set dataset style table.
8021 :
8022 : This method operate exactly as SetStyleTable() except that it
8023 : assumes ownership of the passed table.
8024 :
8025 : This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8026 : and the deprecated OGR_DS_SetStyleTableDirectly().
8027 :
8028 : @param poStyleTable pointer to style table to set
8029 :
8030 : */
8031 0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8032 : {
8033 0 : if (m_poStyleTable)
8034 0 : delete m_poStyleTable;
8035 0 : m_poStyleTable = poStyleTable;
8036 0 : }
8037 :
8038 : /************************************************************************/
8039 : /* SetStyleTable() */
8040 : /************************************************************************/
8041 :
8042 : /**
8043 : \brief Set dataset style table.
8044 :
8045 : This method operate exactly as SetStyleTableDirectly() except
8046 : that it does not assume ownership of the passed table.
8047 :
8048 : This method is the same as the C function GDALDatasetSetStyleTable() and the
8049 : deprecated OGR_DS_SetStyleTable().
8050 :
8051 : @param poStyleTable pointer to style table to set
8052 :
8053 : */
8054 :
8055 1002 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8056 : {
8057 1002 : if (m_poStyleTable)
8058 0 : delete m_poStyleTable;
8059 1002 : if (poStyleTable)
8060 1 : m_poStyleTable = poStyleTable->Clone();
8061 1002 : }
8062 :
8063 : /************************************************************************/
8064 : /* IsGenericSQLDialect() */
8065 : /************************************************************************/
8066 :
8067 : //! @cond Doxygen_Suppress
8068 1780 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8069 : {
8070 3252 : return pszDialect != nullptr &&
8071 3252 : (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8072 : }
8073 :
8074 : //! @endcond
8075 :
8076 : /************************************************************************/
8077 : /* GetLayerCount() */
8078 : /************************************************************************/
8079 :
8080 : /**
8081 : \brief Get the number of layers in this dataset.
8082 :
8083 : This method is the same as the C function GDALDatasetGetLayerCount(),
8084 : and the deprecated OGR_DS_GetLayerCount().
8085 :
8086 : Note that even if this method is const, there is no guarantee it can be
8087 : safely called by concurrent threads on the same GDALDataset object.
8088 :
8089 : @return layer count.
8090 : */
8091 :
8092 122831 : int GDALDataset::GetLayerCount() const
8093 : {
8094 122831 : return 0;
8095 : }
8096 :
8097 : /************************************************************************/
8098 : /* GetLayer() */
8099 : /************************************************************************/
8100 :
8101 : /**
8102 : \fn const GDALDataset::GetLayer(int) const
8103 : \brief Fetch a layer by index.
8104 :
8105 : The returned layer remains owned by the
8106 : GDALDataset and should not be deleted by the application.
8107 :
8108 : Note that even if this method is const, there is no guarantee it can be
8109 : safely called by concurrent threads on the same GDALDataset object.
8110 :
8111 : See GetLayers() for a C++ iterator version of this method.
8112 :
8113 : This method is the same as the C function GDALDatasetGetLayer() and the
8114 : deprecated OGR_DS_GetLayer().
8115 :
8116 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8117 :
8118 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8119 :
8120 : @see GetLayers()
8121 :
8122 : @since GDAL 3.12
8123 : */
8124 :
8125 0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8126 : {
8127 0 : return nullptr;
8128 : }
8129 :
8130 : /**
8131 : \fn GDALDataset::GetLayer(int)
8132 : \brief Fetch a layer by index.
8133 :
8134 : The returned layer remains owned by the
8135 : GDALDataset and should not be deleted by the application.
8136 :
8137 : See GetLayers() for a C++ iterator version of this method.
8138 :
8139 : This method is the same as the C function GDALDatasetGetLayer() and the
8140 : deprecated OGR_DS_GetLayer().
8141 :
8142 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8143 :
8144 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8145 :
8146 : @see GetLayers()
8147 : */
8148 :
8149 : /************************************************************************/
8150 : /* IsLayerPrivate() */
8151 : /************************************************************************/
8152 :
8153 : /**
8154 : \fn GDALDataset::IsLayerPrivate(int)
8155 : \brief Returns true if the layer at the specified index is deemed a private or
8156 : system table, or an internal detail only.
8157 :
8158 : This method is the same as the C function GDALDatasetIsLayerPrivate().
8159 :
8160 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8161 :
8162 : @return true if the layer is a private or system table.
8163 :
8164 : @since GDAL 3.4
8165 : */
8166 :
8167 1024 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8168 : {
8169 1024 : return false;
8170 : }
8171 :
8172 : /************************************************************************/
8173 : /* ResetReading() */
8174 : /************************************************************************/
8175 :
8176 : /**
8177 : \brief Reset feature reading to start on the first feature.
8178 :
8179 : This affects GetNextFeature().
8180 :
8181 : Depending on drivers, this may also have the side effect of calling
8182 : OGRLayer::ResetReading() on the layers of this dataset.
8183 :
8184 : This method is the same as the C function GDALDatasetResetReading().
8185 :
8186 : */
8187 7 : void GDALDataset::ResetReading()
8188 : {
8189 7 : if (!m_poPrivate)
8190 0 : return;
8191 7 : m_poPrivate->nCurrentLayerIdx = 0;
8192 7 : m_poPrivate->nLayerCount = -1;
8193 7 : m_poPrivate->poCurrentLayer = nullptr;
8194 7 : m_poPrivate->nFeatureReadInLayer = 0;
8195 7 : m_poPrivate->nFeatureReadInDataset = 0;
8196 7 : m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8197 7 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8198 : }
8199 :
8200 : /************************************************************************/
8201 : /* GDALDatasetResetReading() */
8202 : /************************************************************************/
8203 :
8204 : /**
8205 : \brief Reset feature reading to start on the first feature.
8206 :
8207 : This affects GDALDatasetGetNextFeature().
8208 :
8209 : Depending on drivers, this may also have the side effect of calling
8210 : OGR_L_ResetReading() on the layers of this dataset.
8211 :
8212 : This method is the same as the C++ method GDALDataset::ResetReading()
8213 :
8214 : @param hDS dataset handle
8215 : */
8216 14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8217 : {
8218 14 : VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8219 :
8220 14 : return GDALDataset::FromHandle(hDS)->ResetReading();
8221 : }
8222 :
8223 : /************************************************************************/
8224 : /* GetNextFeature() */
8225 : /************************************************************************/
8226 :
8227 : /**
8228 : \brief Fetch the next available feature from this dataset.
8229 :
8230 : This method is intended for the few drivers where OGRLayer::GetNextFeature()
8231 : is not efficient, but in general OGRLayer::GetNextFeature() is a more
8232 : natural API.
8233 :
8234 : See GetFeatures() for a C++ iterator version of this method.
8235 :
8236 : The returned feature becomes the responsibility of the caller to
8237 : delete with OGRFeature::DestroyFeature().
8238 :
8239 : Depending on the driver, this method may return features from layers in a
8240 : non sequential way. This is what may happen when the
8241 : ODsCRandomLayerRead capability is declared (for example for the
8242 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8243 : advised to use GDALDataset::GetNextFeature() instead of
8244 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8245 : implementation.
8246 :
8247 : The default implementation, used by most drivers, will
8248 : however iterate over each layer, and then over each feature within this
8249 : layer.
8250 :
8251 : This method takes into account spatial and attribute filters set on layers that
8252 : will be iterated upon.
8253 :
8254 : The ResetReading() method can be used to start at the beginning again.
8255 :
8256 : Depending on drivers, this may also have the side effect of calling
8257 : OGRLayer::GetNextFeature() on the layers of this dataset.
8258 :
8259 : This method is the same as the C function GDALDatasetGetNextFeature().
8260 :
8261 : @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8262 : layer to which the object belongs to, or NULL.
8263 : It is possible that the output of *ppoBelongingLayer
8264 : to be NULL despite the feature not being NULL.
8265 : @param pdfProgressPct a pointer to a double variable to receive the
8266 : percentage progress (in [0,1] range), or NULL.
8267 : On return, the pointed value might be negative if
8268 : determining the progress is not possible.
8269 : @param pfnProgress a progress callback to report progress (for
8270 : GetNextFeature() calls that might have a long
8271 : duration) and offer cancellation possibility, or NULL.
8272 : @param pProgressData user data provided to pfnProgress, or NULL
8273 : @return a feature, or NULL if no more features are available.
8274 : @see GetFeatures()
8275 : */
8276 :
8277 68 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8278 : double *pdfProgressPct,
8279 : GDALProgressFunc pfnProgress,
8280 : void *pProgressData)
8281 : {
8282 68 : if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8283 : {
8284 2 : if (ppoBelongingLayer != nullptr)
8285 2 : *ppoBelongingLayer = nullptr;
8286 2 : if (pdfProgressPct != nullptr)
8287 1 : *pdfProgressPct = 1.0;
8288 2 : if (pfnProgress != nullptr)
8289 0 : pfnProgress(1.0, "", pProgressData);
8290 2 : return nullptr;
8291 : }
8292 :
8293 66 : if (m_poPrivate->poCurrentLayer == nullptr &&
8294 11 : (pdfProgressPct != nullptr || pfnProgress != nullptr))
8295 : {
8296 4 : if (m_poPrivate->nLayerCount < 0)
8297 : {
8298 4 : m_poPrivate->nLayerCount = GetLayerCount();
8299 : }
8300 :
8301 4 : if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8302 : {
8303 4 : m_poPrivate->nTotalFeatures = 0;
8304 8 : for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8305 : {
8306 7 : OGRLayer *poLayer = GetLayer(i);
8307 14 : if (poLayer == nullptr ||
8308 7 : !poLayer->TestCapability(OLCFastFeatureCount))
8309 : {
8310 3 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8311 3 : break;
8312 : }
8313 4 : GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8314 4 : if (nCount < 0)
8315 : {
8316 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8317 0 : break;
8318 : }
8319 4 : m_poPrivate->nTotalFeatures += nCount;
8320 : }
8321 : }
8322 : }
8323 :
8324 : while (true)
8325 : {
8326 82 : if (m_poPrivate->poCurrentLayer == nullptr)
8327 : {
8328 56 : m_poPrivate->poCurrentLayer =
8329 28 : GetLayer(m_poPrivate->nCurrentLayerIdx);
8330 28 : if (m_poPrivate->poCurrentLayer == nullptr)
8331 : {
8332 10 : m_poPrivate->nCurrentLayerIdx = -1;
8333 10 : if (ppoBelongingLayer != nullptr)
8334 7 : *ppoBelongingLayer = nullptr;
8335 10 : if (pdfProgressPct != nullptr)
8336 1 : *pdfProgressPct = 1.0;
8337 10 : return nullptr;
8338 : }
8339 18 : m_poPrivate->poCurrentLayer->ResetReading();
8340 18 : m_poPrivate->nFeatureReadInLayer = 0;
8341 18 : if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8342 : {
8343 0 : if (m_poPrivate->poCurrentLayer->TestCapability(
8344 0 : OLCFastFeatureCount))
8345 0 : m_poPrivate->nTotalFeaturesInLayer =
8346 0 : m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8347 : else
8348 0 : m_poPrivate->nTotalFeaturesInLayer = 0;
8349 : }
8350 : }
8351 72 : OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8352 72 : if (poFeature == nullptr)
8353 : {
8354 16 : m_poPrivate->nCurrentLayerIdx++;
8355 16 : m_poPrivate->poCurrentLayer = nullptr;
8356 16 : continue;
8357 : }
8358 :
8359 56 : m_poPrivate->nFeatureReadInLayer++;
8360 56 : m_poPrivate->nFeatureReadInDataset++;
8361 56 : if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8362 : {
8363 9 : double dfPct = 0.0;
8364 9 : if (m_poPrivate->nTotalFeatures > 0)
8365 : {
8366 4 : dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8367 4 : m_poPrivate->nTotalFeatures;
8368 : }
8369 : else
8370 : {
8371 5 : dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8372 5 : m_poPrivate->nLayerCount;
8373 5 : if (m_poPrivate->nTotalFeaturesInLayer > 0)
8374 : {
8375 0 : dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8376 0 : m_poPrivate->nTotalFeaturesInLayer /
8377 0 : m_poPrivate->nLayerCount;
8378 : }
8379 : }
8380 9 : if (pdfProgressPct)
8381 4 : *pdfProgressPct = dfPct;
8382 9 : if (pfnProgress)
8383 5 : pfnProgress(dfPct, "", nullptr);
8384 : }
8385 :
8386 56 : if (ppoBelongingLayer != nullptr)
8387 51 : *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8388 56 : return poFeature;
8389 16 : }
8390 : }
8391 :
8392 : /************************************************************************/
8393 : /* GDALDatasetGetNextFeature() */
8394 : /************************************************************************/
8395 : /**
8396 : \brief Fetch the next available feature from this dataset.
8397 :
8398 : This method is intended for the few drivers where OGR_L_GetNextFeature()
8399 : is not efficient, but in general OGR_L_GetNextFeature() is a more
8400 : natural API.
8401 :
8402 : The returned feature becomes the responsibility of the caller to
8403 : delete with OGRFeature::DestroyFeature().
8404 :
8405 : Depending on the driver, this method may return features from layers in a
8406 : non sequential way. This is what may happen when the
8407 : ODsCRandomLayerRead capability is declared (for example for the
8408 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8409 : advised to use GDALDataset::GetNextFeature() instead of
8410 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8411 : implementation.
8412 :
8413 : The default implementation, used by most drivers, will
8414 : however iterate over each layer, and then over each feature within this
8415 : layer.
8416 :
8417 : This method takes into account spatial and attribute filters set on layers that
8418 : will be iterated upon.
8419 :
8420 : The ResetReading() method can be used to start at the beginning again.
8421 :
8422 : Depending on drivers, this may also have the side effect of calling
8423 : OGRLayer::GetNextFeature() on the layers of this dataset.
8424 :
8425 : This method is the same as the C++ method GDALDataset::GetNextFeature()
8426 :
8427 : @param hDS dataset handle.
8428 : @param phBelongingLayer a pointer to a OGRLayer* variable to receive the
8429 : layer to which the object belongs to, or NULL.
8430 : It is possible that the output of *ppoBelongingLayer
8431 : to be NULL despite the feature not being NULL.
8432 : @param pdfProgressPct a pointer to a double variable to receive the
8433 : percentage progress (in [0,1] range), or NULL.
8434 : On return, the pointed value might be negative if
8435 : determining the progress is not possible.
8436 : @param pfnProgress a progress callback to report progress (for
8437 : GetNextFeature() calls that might have a long
8438 : duration) and offer cancellation possibility, or NULL
8439 : @param pProgressData user data provided to pfnProgress, or NULL
8440 : @return a feature, or NULL if no more features are available.
8441 : */
8442 1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8443 : OGRLayerH *phBelongingLayer,
8444 : double *pdfProgressPct,
8445 : GDALProgressFunc pfnProgress,
8446 : void *pProgressData)
8447 : {
8448 1917 : VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8449 :
8450 3834 : return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8451 : reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8452 3834 : pfnProgress, pProgressData));
8453 : }
8454 :
8455 : /************************************************************************/
8456 : /* TestCapability() */
8457 : /************************************************************************/
8458 :
8459 : /**
8460 : \fn GDALDataset::TestCapability( const char * pszCap )
8461 : \brief Test if capability is available.
8462 :
8463 : One of the following dataset capability names can be passed into this
8464 : method, and a TRUE or FALSE value will be returned indicating whether or not
8465 : the capability is available for this object.
8466 :
8467 : <ul>
8468 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8469 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8470 : layers.<p>
8471 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8472 : datasource support CreateGeomField() just after layer creation.<p>
8473 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8474 : geometries.<p>
8475 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8476 : transactions.<p>
8477 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8478 : transactions through emulation.<p>
8479 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8480 : GetNextFeature() implementation, potentially returning features from
8481 : layers in a non sequential way.<p>
8482 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8483 : CreateFeature() on layers in a non sequential way.<p>
8484 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8485 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8486 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8487 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8488 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8489 : </ul>
8490 :
8491 : The \#define macro forms of the capability names should be used in preference
8492 : to the strings themselves to avoid misspelling.
8493 :
8494 : This method is the same as the C function GDALDatasetTestCapability() and the
8495 : deprecated OGR_DS_TestCapability().
8496 :
8497 : @param pszCap the capability to test.
8498 :
8499 : @return TRUE if capability available otherwise FALSE.
8500 : */
8501 :
8502 1021 : int GDALDataset::TestCapability(const char *pszCap) const
8503 : {
8504 1021 : if (EQUAL(pszCap, GDsCFastGetExtent) ||
8505 1019 : EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8506 : {
8507 4 : for (auto &&poLayer : GetLayers())
8508 : {
8509 2 : if (!poLayer->TestCapability(OLCFastGetExtent))
8510 2 : return FALSE;
8511 : }
8512 2 : return TRUE;
8513 : }
8514 1017 : return FALSE;
8515 : }
8516 :
8517 : /************************************************************************/
8518 : /* GDALDatasetTestCapability() */
8519 : /************************************************************************/
8520 :
8521 : /**
8522 : \brief Test if capability is available.
8523 :
8524 : One of the following dataset capability names can be passed into this
8525 : function, and a TRUE or FALSE value will be returned indicating whether or not
8526 : the capability is available for this object.
8527 :
8528 : <ul>
8529 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8530 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8531 : layers.<p>
8532 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8533 : datasource support CreateGeomField() just after layer creation.<p>
8534 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8535 : geometries.<p>
8536 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8537 : transactions.<p>
8538 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8539 : transactions through emulation.<p>
8540 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8541 : GetNextFeature() implementation, potentially returning features from
8542 : layers in a non sequential way.<p>
8543 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8544 : CreateFeature() on layers in a non sequential way.<p>
8545 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8546 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8547 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8548 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8549 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8550 : </ul>
8551 :
8552 : The \#define macro forms of the capability names should be used in preference
8553 : to the strings themselves to avoid misspelling.
8554 :
8555 : This function is the same as the C++ method GDALDataset::TestCapability()
8556 :
8557 :
8558 : @param hDS the dataset handle.
8559 : @param pszCap the capability to test.
8560 :
8561 : @return TRUE if capability available otherwise FALSE.
8562 : */
8563 132 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8564 :
8565 : {
8566 132 : VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8567 132 : VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8568 :
8569 132 : return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8570 : }
8571 :
8572 : /************************************************************************/
8573 : /* StartTransaction() */
8574 : /************************************************************************/
8575 :
8576 : /**
8577 : \fn GDALDataset::StartTransaction(int)
8578 : \brief For datasources which support transactions, StartTransaction creates a
8579 : `transaction.
8580 :
8581 : If starting the transaction fails, will return
8582 : OGRERR_FAILURE. Datasources which do not support transactions will
8583 : always return OGRERR_UNSUPPORTED_OPERATION.
8584 :
8585 : Nested transactions are not supported.
8586 :
8587 : All changes done after the start of the transaction are definitely applied in
8588 : the datasource if CommitTransaction() is called. They may be canceled by
8589 : calling RollbackTransaction() instead.
8590 :
8591 : At the time of writing, transactions only apply on vector layers.
8592 :
8593 : Datasets that support transactions will advertise the ODsCTransactions
8594 : capability. Use of transactions at dataset level is generally preferred to
8595 : transactions at layer level, whose scope is rarely limited to the layer from
8596 : which it was started.
8597 :
8598 : In case StartTransaction() fails, neither CommitTransaction() or
8599 : RollbackTransaction() should be called.
8600 :
8601 : If an error occurs after a successful StartTransaction(), the whole transaction
8602 : may or may not be implicitly canceled, depending on drivers. (e.g. the PG
8603 : driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8604 : an explicit call to RollbackTransaction() should be done to keep things
8605 : balanced.
8606 :
8607 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8608 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8609 : with significant overhead, in which case the user must explicitly allow for
8610 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8611 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8612 : ODsCTransactions).
8613 :
8614 : This function is the same as the C function GDALDatasetStartTransaction().
8615 :
8616 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8617 : transaction
8618 : mechanism is acceptable.
8619 :
8620 : @return OGRERR_NONE on success.
8621 : */
8622 :
8623 37 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8624 : {
8625 37 : return OGRERR_UNSUPPORTED_OPERATION;
8626 : }
8627 :
8628 : /************************************************************************/
8629 : /* GDALDatasetStartTransaction() */
8630 : /************************************************************************/
8631 :
8632 : /**
8633 : \brief For datasources which support transactions, StartTransaction creates a
8634 : transaction.
8635 :
8636 : If starting the transaction fails, will return
8637 : OGRERR_FAILURE. Datasources which do not support transactions will
8638 : always return OGRERR_UNSUPPORTED_OPERATION.
8639 :
8640 : Nested transactions are not supported.
8641 :
8642 : All changes done after the start of the transaction are definitely applied in
8643 : the datasource if CommitTransaction() is called. They may be canceled by
8644 : calling RollbackTransaction() instead.
8645 :
8646 : At the time of writing, transactions only apply on vector layers.
8647 :
8648 : Datasets that support transactions will advertise the ODsCTransactions
8649 : capability.
8650 : Use of transactions at dataset level is generally preferred to transactions at
8651 : layer level, whose scope is rarely limited to the layer from which it was
8652 : started.
8653 :
8654 : In case StartTransaction() fails, neither CommitTransaction() or
8655 : RollbackTransaction() should be called.
8656 :
8657 : If an error occurs after a successful StartTransaction(), the whole
8658 : transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8659 : the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8660 : error, an explicit call to RollbackTransaction() should be done to keep things
8661 : balanced.
8662 :
8663 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8664 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8665 : with significant overhead, in which case the user must explicitly allow for
8666 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8667 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8668 : ODsCTransactions).
8669 :
8670 : This function is the same as the C++ method GDALDataset::StartTransaction()
8671 :
8672 : @param hDS the dataset handle.
8673 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8674 : transaction
8675 : mechanism is acceptable.
8676 :
8677 : @return OGRERR_NONE on success.
8678 : */
8679 106 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8680 : {
8681 106 : VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8682 : OGRERR_INVALID_HANDLE);
8683 :
8684 : #ifdef OGRAPISPY_ENABLED
8685 106 : if (bOGRAPISpyEnabled)
8686 2 : OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8687 : #endif
8688 :
8689 106 : return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8690 : }
8691 :
8692 : /************************************************************************/
8693 : /* CommitTransaction() */
8694 : /************************************************************************/
8695 :
8696 : /**
8697 : \brief For datasources which support transactions, CommitTransaction commits a
8698 : transaction.
8699 :
8700 : If no transaction is active, or the commit fails, will return
8701 : OGRERR_FAILURE. Datasources which do not support transactions will
8702 : always return OGRERR_UNSUPPORTED_OPERATION.
8703 :
8704 : Depending on drivers, this may or may not abort layer sequential readings that
8705 : are active.
8706 :
8707 : This function is the same as the C function GDALDatasetCommitTransaction().
8708 :
8709 : @return OGRERR_NONE on success.
8710 : */
8711 52 : OGRErr GDALDataset::CommitTransaction()
8712 : {
8713 52 : return OGRERR_UNSUPPORTED_OPERATION;
8714 : }
8715 :
8716 : /************************************************************************/
8717 : /* GDALDatasetCommitTransaction() */
8718 : /************************************************************************/
8719 :
8720 : /**
8721 : \brief For datasources which support transactions, CommitTransaction commits a
8722 : transaction.
8723 :
8724 : If no transaction is active, or the commit fails, will return
8725 : OGRERR_FAILURE. Datasources which do not support transactions will
8726 : always return OGRERR_UNSUPPORTED_OPERATION.
8727 :
8728 : Depending on drivers, this may or may not abort layer sequential readings that
8729 : are active.
8730 :
8731 : This function is the same as the C++ method GDALDataset::CommitTransaction()
8732 :
8733 : @return OGRERR_NONE on success.
8734 : */
8735 77 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8736 : {
8737 77 : VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8738 : OGRERR_INVALID_HANDLE);
8739 :
8740 : #ifdef OGRAPISPY_ENABLED
8741 77 : if (bOGRAPISpyEnabled)
8742 2 : OGRAPISpy_Dataset_CommitTransaction(hDS);
8743 : #endif
8744 :
8745 77 : return GDALDataset::FromHandle(hDS)->CommitTransaction();
8746 : }
8747 :
8748 : /************************************************************************/
8749 : /* RollbackTransaction() */
8750 : /************************************************************************/
8751 :
8752 : /**
8753 : \brief For datasources which support transactions, RollbackTransaction will
8754 : roll back a datasource to its state before the start of the current
8755 : transaction.
8756 : If no transaction is active, or the rollback fails, will return
8757 : OGRERR_FAILURE. Datasources which do not support transactions will
8758 : always return OGRERR_UNSUPPORTED_OPERATION.
8759 :
8760 : This function is the same as the C function GDALDatasetRollbackTransaction().
8761 :
8762 : @return OGRERR_NONE on success.
8763 : */
8764 2 : OGRErr GDALDataset::RollbackTransaction()
8765 : {
8766 2 : return OGRERR_UNSUPPORTED_OPERATION;
8767 : }
8768 :
8769 : /************************************************************************/
8770 : /* GDALDatasetRollbackTransaction() */
8771 : /************************************************************************/
8772 :
8773 : /**
8774 : \brief For datasources which support transactions, RollbackTransaction will
8775 : roll back a datasource to its state before the start of the current
8776 : transaction.
8777 : If no transaction is active, or the rollback fails, will return
8778 : OGRERR_FAILURE. Datasources which do not support transactions will
8779 : always return OGRERR_UNSUPPORTED_OPERATION.
8780 :
8781 : This function is the same as the C++ method GDALDataset::RollbackTransaction().
8782 :
8783 : @return OGRERR_NONE on success.
8784 : */
8785 44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8786 : {
8787 44 : VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8788 : OGRERR_INVALID_HANDLE);
8789 :
8790 : #ifdef OGRAPISPY_ENABLED
8791 44 : if (bOGRAPISpyEnabled)
8792 2 : OGRAPISpy_Dataset_RollbackTransaction(hDS);
8793 : #endif
8794 :
8795 44 : return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8796 : }
8797 :
8798 : //! @cond Doxygen_Suppress
8799 :
8800 : /************************************************************************/
8801 : /* ShareLockWithParentDataset() */
8802 : /************************************************************************/
8803 :
8804 : /* To be used typically by the GTiff driver to link overview datasets */
8805 : /* with their main dataset, so that they share the same lock */
8806 : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
8807 : /* The parent dataset should remain alive while the this dataset is alive */
8808 :
8809 2531 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8810 : {
8811 2531 : if (m_poPrivate != nullptr)
8812 : {
8813 2531 : m_poPrivate->poParentDataset = poParentDataset;
8814 : }
8815 2531 : }
8816 :
8817 : /************************************************************************/
8818 : /* SetQueryLoggerFunc() */
8819 : /************************************************************************/
8820 :
8821 0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8822 : CPL_UNUSED void *context)
8823 : {
8824 0 : return false;
8825 : }
8826 :
8827 : /************************************************************************/
8828 : /* EnterReadWrite() */
8829 : /************************************************************************/
8830 :
8831 8315700 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8832 : {
8833 16631400 : if (m_poPrivate == nullptr ||
8834 8315700 : IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8835 11991 : return FALSE;
8836 :
8837 8303710 : if (m_poPrivate->poParentDataset)
8838 242703 : return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8839 :
8840 8061010 : if (eAccess == GA_Update)
8841 : {
8842 2449290 : if (m_poPrivate->eStateReadWriteMutex ==
8843 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8844 : {
8845 : // In case dead-lock would occur, which is not impossible,
8846 : // this can be used to prevent it, but at the risk of other
8847 : // issues.
8848 11024 : if (CPLTestBool(
8849 : CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8850 : {
8851 11024 : m_poPrivate->eStateReadWriteMutex =
8852 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8853 : }
8854 : else
8855 : {
8856 0 : m_poPrivate->eStateReadWriteMutex =
8857 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8858 : }
8859 : }
8860 2449290 : if (m_poPrivate->eStateReadWriteMutex ==
8861 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8862 : {
8863 : // There should be no race related to creating this mutex since
8864 : // it should be first created through IWriteBlock() / IRasterIO()
8865 : // and then GDALRasterBlock might call it from another thread.
8866 : #ifdef DEBUG_VERBOSE
8867 : CPLDebug("GDAL",
8868 : "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8869 : CPLGetPID(), GetDescription());
8870 : #endif
8871 1563560 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8872 :
8873 : const int nCountMutex =
8874 1563560 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8875 1563560 : if (nCountMutex == 0 && eRWFlag == GF_Read)
8876 : {
8877 539750 : CPLReleaseMutex(m_poPrivate->hMutex);
8878 1725390 : for (int i = 0; i < nBands; i++)
8879 : {
8880 1185640 : auto blockCache = papoBands[i]->poBandBlockCache;
8881 1185640 : if (blockCache)
8882 824392 : blockCache->WaitCompletionPendingTasks();
8883 : }
8884 539750 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8885 : }
8886 :
8887 1563560 : return TRUE;
8888 : }
8889 : }
8890 6497450 : return FALSE;
8891 : }
8892 :
8893 : /************************************************************************/
8894 : /* LeaveReadWrite() */
8895 : /************************************************************************/
8896 :
8897 1792580 : void GDALDataset::LeaveReadWrite()
8898 : {
8899 1792580 : if (m_poPrivate)
8900 : {
8901 1792580 : if (m_poPrivate->poParentDataset)
8902 : {
8903 229021 : m_poPrivate->poParentDataset->LeaveReadWrite();
8904 229021 : return;
8905 : }
8906 :
8907 1563560 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8908 1563560 : CPLReleaseMutex(m_poPrivate->hMutex);
8909 : #ifdef DEBUG_VERBOSE
8910 : CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8911 : CPLGetPID(), GetDescription());
8912 : #endif
8913 : }
8914 : }
8915 :
8916 : /************************************************************************/
8917 : /* InitRWLock() */
8918 : /************************************************************************/
8919 :
8920 4009260 : void GDALDataset::InitRWLock()
8921 : {
8922 4009260 : if (m_poPrivate)
8923 : {
8924 4009260 : if (m_poPrivate->poParentDataset)
8925 : {
8926 8608 : m_poPrivate->poParentDataset->InitRWLock();
8927 8608 : return;
8928 : }
8929 :
8930 4000650 : if (m_poPrivate->eStateReadWriteMutex ==
8931 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8932 : {
8933 1 : if (EnterReadWrite(GF_Write))
8934 1 : LeaveReadWrite();
8935 : }
8936 : }
8937 : }
8938 :
8939 : /************************************************************************/
8940 : /* DisableReadWriteMutex() */
8941 : /************************************************************************/
8942 :
8943 : // The mutex logic is broken in multi-threaded situations, for example
8944 : // with 2 WarpedVRT datasets being read at the same time. In that
8945 : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8946 : // to disable it.
8947 36231 : void GDALDataset::DisableReadWriteMutex()
8948 : {
8949 36231 : if (m_poPrivate)
8950 : {
8951 36231 : if (m_poPrivate->poParentDataset)
8952 : {
8953 0 : m_poPrivate->poParentDataset->DisableReadWriteMutex();
8954 0 : return;
8955 : }
8956 :
8957 36231 : m_poPrivate->eStateReadWriteMutex =
8958 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8959 : }
8960 : }
8961 :
8962 : /************************************************************************/
8963 : /* TemporarilyDropReadWriteLock() */
8964 : /************************************************************************/
8965 :
8966 3437630 : void GDALDataset::TemporarilyDropReadWriteLock()
8967 : {
8968 3437630 : if (m_poPrivate == nullptr)
8969 0 : return;
8970 :
8971 3437630 : if (m_poPrivate->poParentDataset)
8972 : {
8973 26397 : m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8974 26397 : return;
8975 : }
8976 :
8977 : #ifndef __COVERITY__
8978 3411240 : if (m_poPrivate->hMutex)
8979 : {
8980 : #ifdef DEBUG_VERBOSE
8981 : CPLDebug("GDAL",
8982 : "[Thread " CPL_FRMT_GIB "] "
8983 : "Temporarily drop RW mutex for %s",
8984 : CPLGetPID(), GetDescription());
8985 : #endif
8986 422957 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8987 : const int nCount =
8988 422957 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8989 : #ifdef DEBUG_EXTRA
8990 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8991 : #endif
8992 1276640 : for (int i = 0; i < nCount + 1; i++)
8993 : {
8994 : // The mutex is recursive
8995 853680 : CPLReleaseMutex(m_poPrivate->hMutex);
8996 : }
8997 : }
8998 : #endif
8999 : }
9000 :
9001 : /************************************************************************/
9002 : /* ReacquireReadWriteLock() */
9003 : /************************************************************************/
9004 :
9005 3437630 : void GDALDataset::ReacquireReadWriteLock()
9006 : {
9007 3437630 : if (m_poPrivate == nullptr)
9008 0 : return;
9009 :
9010 3437630 : if (m_poPrivate->poParentDataset)
9011 : {
9012 26397 : m_poPrivate->poParentDataset->ReacquireReadWriteLock();
9013 26397 : return;
9014 : }
9015 :
9016 : #ifndef __COVERITY__
9017 3411240 : if (m_poPrivate->hMutex)
9018 : {
9019 : #ifdef DEBUG_VERBOSE
9020 : CPLDebug("GDAL",
9021 : "[Thread " CPL_FRMT_GIB "] "
9022 : "Reacquire temporarily dropped RW mutex for %s",
9023 : CPLGetPID(), GetDescription());
9024 : #endif
9025 422958 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9026 : const int nCount =
9027 422958 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9028 : #ifdef DEBUG_EXTRA
9029 : CPLAssert(nCount ==
9030 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9031 : #endif
9032 422958 : if (nCount == 0)
9033 18278 : CPLReleaseMutex(m_poPrivate->hMutex);
9034 449001 : for (int i = 0; i < nCount - 1; i++)
9035 : {
9036 : // The mutex is recursive
9037 26043 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9038 : }
9039 : }
9040 : #endif
9041 : }
9042 :
9043 : /************************************************************************/
9044 : /* AcquireMutex() */
9045 : /************************************************************************/
9046 :
9047 196 : int GDALDataset::AcquireMutex()
9048 : {
9049 196 : if (m_poPrivate == nullptr)
9050 0 : return 0;
9051 196 : if (m_poPrivate->poParentDataset)
9052 : {
9053 0 : return m_poPrivate->poParentDataset->AcquireMutex();
9054 : }
9055 :
9056 196 : return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9057 : }
9058 :
9059 : /************************************************************************/
9060 : /* ReleaseMutex() */
9061 : /************************************************************************/
9062 :
9063 196 : void GDALDataset::ReleaseMutex()
9064 : {
9065 196 : if (m_poPrivate)
9066 : {
9067 196 : if (m_poPrivate->poParentDataset)
9068 : {
9069 0 : m_poPrivate->poParentDataset->ReleaseMutex();
9070 0 : return;
9071 : }
9072 :
9073 196 : CPLReleaseMutex(m_poPrivate->hMutex);
9074 : }
9075 : }
9076 :
9077 : //! @endcond
9078 :
9079 : /************************************************************************/
9080 : /* GDALDataset::Features::Iterator::Private */
9081 : /************************************************************************/
9082 :
9083 : struct GDALDataset::Features::Iterator::Private
9084 : {
9085 : GDALDataset::FeatureLayerPair m_oPair{};
9086 : GDALDataset *m_poDS = nullptr;
9087 : bool m_bEOF = true;
9088 : };
9089 :
9090 4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9091 4 : : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9092 : {
9093 4 : m_poPrivate->m_poDS = poDS;
9094 4 : if (bStart)
9095 : {
9096 2 : poDS->ResetReading();
9097 4 : m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9098 2 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9099 2 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9100 : }
9101 4 : }
9102 :
9103 : GDALDataset::Features::Iterator::~Iterator() = default;
9104 :
9105 : const GDALDataset::FeatureLayerPair &
9106 20 : GDALDataset::Features::Iterator::operator*() const
9107 : {
9108 20 : return m_poPrivate->m_oPair;
9109 : }
9110 :
9111 20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9112 : {
9113 40 : m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9114 20 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9115 20 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9116 20 : return *this;
9117 : }
9118 :
9119 22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9120 : {
9121 22 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9122 : }
9123 :
9124 : /************************************************************************/
9125 : /* GetFeatures() */
9126 : /************************************************************************/
9127 :
9128 : /** Function that return an iterable object over features in the dataset
9129 : * layer.
9130 : *
9131 : * This is a C++ iterator friendly version of GetNextFeature().
9132 : *
9133 : * Using this iterator for standard range-based loops is safe, but
9134 : * due to implementation limitations, you shouldn't try to access
9135 : * (dereference) more than one iterator step at a time, since the
9136 : * FeatureLayerPair reference which is returned is reused.
9137 : *
9138 : * Typical use is:
9139 : * \code{.cpp}
9140 : * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9141 : * {
9142 : * std::cout << "Feature of layer " <<
9143 : * oFeatureLayerPair.layer->GetName() << std::endl;
9144 : * oFeatureLayerPair.feature->DumpReadable();
9145 : * }
9146 : * \endcode
9147 : *
9148 : * @see GetNextFeature()
9149 : *
9150 : */
9151 2 : GDALDataset::Features GDALDataset::GetFeatures()
9152 : {
9153 2 : return Features(this);
9154 : }
9155 :
9156 : /************************************************************************/
9157 : /* begin() */
9158 : /************************************************************************/
9159 :
9160 : /**
9161 : \brief Return beginning of feature iterator.
9162 :
9163 : */
9164 :
9165 2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9166 : {
9167 2 : return {m_poSelf, true};
9168 : }
9169 :
9170 : /************************************************************************/
9171 : /* end() */
9172 : /************************************************************************/
9173 :
9174 : /**
9175 : \brief Return end of feature iterator.
9176 :
9177 : */
9178 :
9179 2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9180 : {
9181 2 : return {m_poSelf, false};
9182 : }
9183 :
9184 : /************************************************************************/
9185 : /* GDALDataset::Layers::Iterator::Private */
9186 : /************************************************************************/
9187 :
9188 : struct GDALDataset::Layers::Iterator::Private
9189 : {
9190 : OGRLayer *m_poLayer = nullptr;
9191 : int m_iCurLayer = 0;
9192 : int m_nLayerCount = 0;
9193 : GDALDataset *m_poDS = nullptr;
9194 : };
9195 :
9196 2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9197 : {
9198 2 : }
9199 :
9200 : // False positive of cppcheck 1.72
9201 : // cppcheck-suppress uninitMemberVar
9202 9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9203 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9204 : {
9205 9 : }
9206 :
9207 5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9208 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9209 : {
9210 5 : }
9211 :
9212 109854 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9213 109854 : : m_poPrivate(new Private())
9214 : {
9215 109854 : m_poPrivate->m_poDS = poDS;
9216 109854 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9217 109854 : if (bStart)
9218 : {
9219 54929 : if (m_poPrivate->m_nLayerCount)
9220 46448 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9221 : }
9222 : else
9223 : {
9224 54925 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9225 : }
9226 109854 : }
9227 :
9228 : GDALDataset::Layers::Iterator::~Iterator() = default;
9229 :
9230 : // False positive of cppcheck 1.72
9231 : // cppcheck-suppress operatorEqVarError
9232 : GDALDataset::Layers::Iterator &
9233 1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9234 : {
9235 1 : *m_poPrivate = *oOther.m_poPrivate;
9236 1 : return *this;
9237 : }
9238 :
9239 3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9240 : GDALDataset::Layers::Iterator &&oOther) noexcept
9241 : {
9242 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9243 3 : return *this;
9244 : }
9245 :
9246 1800500 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9247 : {
9248 1800500 : return m_poPrivate->m_poLayer;
9249 : }
9250 :
9251 1786560 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9252 : {
9253 1786560 : m_poPrivate->m_iCurLayer++;
9254 1786560 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9255 : {
9256 1754060 : m_poPrivate->m_poLayer =
9257 1754060 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9258 : }
9259 : else
9260 : {
9261 32505 : m_poPrivate->m_poLayer = nullptr;
9262 : }
9263 1786560 : return *this;
9264 : }
9265 :
9266 2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9267 : {
9268 2 : GDALDataset::Layers::Iterator temp = *this;
9269 2 : ++(*this);
9270 2 : return temp;
9271 : }
9272 :
9273 1841480 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9274 : {
9275 1841480 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9276 : }
9277 :
9278 : /************************************************************************/
9279 : /* GetLayers() */
9280 : /************************************************************************/
9281 :
9282 : /** Function that returns an iterable object over layers in the dataset.
9283 : *
9284 : * This is a C++ iterator friendly version of GetLayer().
9285 : *
9286 : * Typical use is:
9287 : * \code{.cpp}
9288 : * for( auto&& poLayer: poDS->GetLayers() )
9289 : * {
9290 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9291 : * }
9292 : * \endcode
9293 : *
9294 : * @see GetLayer()
9295 : *
9296 : */
9297 54930 : GDALDataset::Layers GDALDataset::GetLayers()
9298 : {
9299 54930 : return Layers(this);
9300 : }
9301 :
9302 : /************************************************************************/
9303 : /* begin() */
9304 : /************************************************************************/
9305 :
9306 : /**
9307 : \brief Return beginning of layer iterator.
9308 :
9309 : */
9310 :
9311 54929 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9312 : {
9313 54929 : return {m_poSelf, true};
9314 : }
9315 :
9316 : /************************************************************************/
9317 : /* end() */
9318 : /************************************************************************/
9319 :
9320 : /**
9321 : \brief Return end of layer iterator.
9322 :
9323 : */
9324 :
9325 54925 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9326 : {
9327 54925 : return {m_poSelf, false};
9328 : }
9329 :
9330 : /************************************************************************/
9331 : /* size() */
9332 : /************************************************************************/
9333 :
9334 : /**
9335 : \brief Get the number of layers in this dataset.
9336 :
9337 : @return layer count.
9338 :
9339 : */
9340 :
9341 1 : size_t GDALDataset::Layers::size() const
9342 : {
9343 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9344 : }
9345 :
9346 : /************************************************************************/
9347 : /* operator[]() */
9348 : /************************************************************************/
9349 : /**
9350 : \brief Fetch a layer by index.
9351 :
9352 : The returned layer remains owned by the
9353 : GDALDataset and should not be deleted by the application.
9354 :
9355 : @param iLayer a layer number between 0 and size()-1.
9356 :
9357 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9358 :
9359 : */
9360 :
9361 9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9362 : {
9363 9 : return m_poSelf->GetLayer(iLayer);
9364 : }
9365 :
9366 : /************************************************************************/
9367 : /* operator[]() */
9368 : /************************************************************************/
9369 : /**
9370 : \brief Fetch a layer by index.
9371 :
9372 : The returned layer remains owned by the
9373 : GDALDataset and should not be deleted by the application.
9374 :
9375 : @param iLayer a layer number between 0 and size()-1.
9376 :
9377 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9378 :
9379 : */
9380 :
9381 1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9382 : {
9383 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9384 : }
9385 :
9386 : /************************************************************************/
9387 : /* operator[]() */
9388 : /************************************************************************/
9389 : /**
9390 : \brief Fetch a layer by name.
9391 :
9392 : The returned layer remains owned by the
9393 : GDALDataset and should not be deleted by the application.
9394 :
9395 : @param pszLayerName layer name
9396 :
9397 : @return the layer, or nullptr if pszLayerName does not match with a layer
9398 :
9399 : */
9400 :
9401 1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9402 : {
9403 1 : return m_poSelf->GetLayerByName(pszLayerName);
9404 : }
9405 :
9406 : /************************************************************************/
9407 : /* GDALDataset::ConstLayers::Iterator::Private */
9408 : /************************************************************************/
9409 :
9410 : struct GDALDataset::ConstLayers::Iterator::Private
9411 : {
9412 : const OGRLayer *m_poLayer = nullptr;
9413 : int m_iCurLayer = 0;
9414 : int m_nLayerCount = 0;
9415 : const GDALDataset *m_poDS = nullptr;
9416 : };
9417 :
9418 2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9419 : {
9420 2 : }
9421 :
9422 : // False positive of cppcheck 1.72
9423 : // cppcheck-suppress uninitMemberVar
9424 9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9425 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9426 : {
9427 9 : }
9428 :
9429 5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9430 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9431 : {
9432 5 : }
9433 :
9434 35838 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9435 35838 : bool bStart)
9436 35838 : : m_poPrivate(new Private())
9437 : {
9438 35838 : m_poPrivate->m_poDS = poDS;
9439 35838 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9440 35838 : if (bStart)
9441 : {
9442 17921 : if (m_poPrivate->m_nLayerCount)
9443 228 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9444 : }
9445 : else
9446 : {
9447 17917 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9448 : }
9449 35838 : }
9450 :
9451 : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9452 :
9453 : // False positive of cppcheck 1.72
9454 : // cppcheck-suppress operatorEqVarError
9455 : GDALDataset::ConstLayers::Iterator &
9456 1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9457 : {
9458 1 : *m_poPrivate = *oOther.m_poPrivate;
9459 1 : return *this;
9460 : }
9461 :
9462 : GDALDataset::ConstLayers::Iterator &
9463 3 : GDALDataset::ConstLayers::Iterator::operator=(
9464 : GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9465 : {
9466 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9467 3 : return *this;
9468 : }
9469 :
9470 16186 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9471 : {
9472 16186 : return m_poPrivate->m_poLayer;
9473 : }
9474 :
9475 : GDALDataset::ConstLayers::Iterator &
9476 16181 : GDALDataset::ConstLayers::Iterator::operator++()
9477 : {
9478 16181 : m_poPrivate->m_iCurLayer++;
9479 16181 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9480 : {
9481 15964 : m_poPrivate->m_poLayer =
9482 15964 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9483 : }
9484 : else
9485 : {
9486 217 : m_poPrivate->m_poLayer = nullptr;
9487 : }
9488 16181 : return *this;
9489 : }
9490 :
9491 : GDALDataset::ConstLayers::Iterator
9492 2 : GDALDataset::ConstLayers::Iterator::operator++(int)
9493 : {
9494 2 : GDALDataset::ConstLayers::Iterator temp = *this;
9495 2 : ++(*this);
9496 2 : return temp;
9497 : }
9498 :
9499 34092 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9500 : {
9501 34092 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9502 : }
9503 :
9504 : /************************************************************************/
9505 : /* GetLayers() */
9506 : /************************************************************************/
9507 :
9508 : /** Function that returns an iterable object over layers in the dataset.
9509 : *
9510 : * This is a C++ iterator friendly version of GetLayer().
9511 : *
9512 : * Typical use is:
9513 : * \code{.cpp}
9514 : * for( auto&& poLayer: poDS->GetLayers() )
9515 : * {
9516 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9517 : * }
9518 : * \endcode
9519 : *
9520 : * @see GetLayer()
9521 : *
9522 : * @since GDAL 3.12
9523 : */
9524 17922 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
9525 : {
9526 17922 : return ConstLayers(this);
9527 : }
9528 :
9529 : /************************************************************************/
9530 : /* begin() */
9531 : /************************************************************************/
9532 :
9533 : /**
9534 : \brief Return beginning of layer iterator.
9535 :
9536 : @since GDAL 3.12
9537 : */
9538 :
9539 17921 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9540 : {
9541 17921 : return {m_poSelf, true};
9542 : }
9543 :
9544 : /************************************************************************/
9545 : /* end() */
9546 : /************************************************************************/
9547 :
9548 : /**
9549 : \brief Return end of layer iterator.
9550 :
9551 : @since GDAL 3.12
9552 : */
9553 :
9554 17917 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9555 : {
9556 17917 : return {m_poSelf, false};
9557 : }
9558 :
9559 : /************************************************************************/
9560 : /* size() */
9561 : /************************************************************************/
9562 :
9563 : /**
9564 : \brief Get the number of layers in this dataset.
9565 :
9566 : @return layer count.
9567 :
9568 : @since GDAL 3.12
9569 : */
9570 :
9571 1 : size_t GDALDataset::ConstLayers::size() const
9572 : {
9573 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9574 : }
9575 :
9576 : /************************************************************************/
9577 : /* operator[]() */
9578 : /************************************************************************/
9579 : /**
9580 : \brief Fetch a layer by index.
9581 :
9582 : The returned layer remains owned by the
9583 : GDALDataset and should not be deleted by the application.
9584 :
9585 : @param iLayer a layer number between 0 and size()-1.
9586 :
9587 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9588 :
9589 : @since GDAL 3.12
9590 : */
9591 :
9592 9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9593 : {
9594 9 : return m_poSelf->GetLayer(iLayer);
9595 : }
9596 :
9597 : /************************************************************************/
9598 : /* operator[]() */
9599 : /************************************************************************/
9600 : /**
9601 : \brief Fetch a layer by index.
9602 :
9603 : The returned layer remains owned by the
9604 : GDALDataset and should not be deleted by the application.
9605 :
9606 : @param iLayer a layer number between 0 and size()-1.
9607 :
9608 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9609 :
9610 : @since GDAL 3.12
9611 : */
9612 :
9613 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9614 : {
9615 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9616 : }
9617 :
9618 : /************************************************************************/
9619 : /* operator[]() */
9620 : /************************************************************************/
9621 : /**
9622 : \brief Fetch a layer by name.
9623 :
9624 : The returned layer remains owned by the
9625 : GDALDataset and should not be deleted by the application.
9626 :
9627 : @param pszLayerName layer name
9628 :
9629 : @return the layer, or nullptr if pszLayerName does not match with a layer
9630 :
9631 : @since GDAL 3.12
9632 : */
9633 :
9634 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9635 : {
9636 1 : return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9637 : }
9638 :
9639 : /************************************************************************/
9640 : /* GDALDataset::Bands::Iterator::Private */
9641 : /************************************************************************/
9642 :
9643 : struct GDALDataset::Bands::Iterator::Private
9644 : {
9645 : GDALRasterBand *m_poBand = nullptr;
9646 : int m_iCurBand = 0;
9647 : int m_nBandCount = 0;
9648 : GDALDataset *m_poDS = nullptr;
9649 : };
9650 :
9651 32 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9652 32 : : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9653 : {
9654 32 : m_poPrivate->m_poDS = poDS;
9655 32 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9656 32 : if (bStart)
9657 : {
9658 16 : if (m_poPrivate->m_nBandCount)
9659 16 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9660 : }
9661 : else
9662 : {
9663 16 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9664 : }
9665 32 : }
9666 :
9667 : GDALDataset::Bands::Iterator::~Iterator() = default;
9668 :
9669 18 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9670 : {
9671 18 : return m_poPrivate->m_poBand;
9672 : }
9673 :
9674 4 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9675 : {
9676 4 : m_poPrivate->m_iCurBand++;
9677 4 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9678 : {
9679 2 : m_poPrivate->m_poBand =
9680 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9681 : }
9682 : else
9683 : {
9684 2 : m_poPrivate->m_poBand = nullptr;
9685 : }
9686 4 : return *this;
9687 : }
9688 :
9689 20 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9690 : {
9691 20 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9692 : }
9693 :
9694 : /************************************************************************/
9695 : /* GetBands() */
9696 : /************************************************************************/
9697 :
9698 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9699 : *
9700 : * This is a C++ iterator friendly version of GetRasterBand().
9701 : *
9702 : * Typical use is:
9703 : * \code{.cpp}
9704 : * for( auto&& poBand: poDS->GetBands() )
9705 : * {
9706 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9707 : * }
9708 : * \endcode
9709 : *
9710 : * @see GetRasterBand()
9711 : *
9712 : */
9713 20 : GDALDataset::Bands GDALDataset::GetBands()
9714 : {
9715 20 : return Bands(this);
9716 : }
9717 :
9718 : /************************************************************************/
9719 : /* begin() */
9720 : /************************************************************************/
9721 :
9722 : /**
9723 : \brief Return beginning of band iterator.
9724 :
9725 : */
9726 :
9727 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9728 : {
9729 16 : return {m_poSelf, true};
9730 : }
9731 :
9732 : /************************************************************************/
9733 : /* end() */
9734 : /************************************************************************/
9735 :
9736 : /**
9737 : \brief Return end of band iterator.
9738 :
9739 : */
9740 :
9741 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9742 : {
9743 16 : return {m_poSelf, false};
9744 : }
9745 :
9746 : /************************************************************************/
9747 : /* size() */
9748 : /************************************************************************/
9749 :
9750 : /**
9751 : \brief Get the number of raster bands in this dataset.
9752 :
9753 : @return raster band count.
9754 :
9755 : */
9756 :
9757 2 : size_t GDALDataset::Bands::size() const
9758 : {
9759 2 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9760 : }
9761 :
9762 : /************************************************************************/
9763 : /* operator[]() */
9764 : /************************************************************************/
9765 : /**
9766 : \brief Fetch a raster band by index.
9767 :
9768 : The returned band remains owned by the
9769 : GDALDataset and should not be deleted by the application.
9770 :
9771 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9772 : consistent with the conventions of C/C++, i.e. starting at 0.
9773 :
9774 : @param iBand a band index between 0 and size()-1.
9775 :
9776 : @return the band, or nullptr if iBand is out of range or an error occurs.
9777 :
9778 : */
9779 :
9780 1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9781 : {
9782 1 : return m_poSelf->GetRasterBand(1 + iBand);
9783 : }
9784 :
9785 : /************************************************************************/
9786 : /* operator[]() */
9787 : /************************************************************************/
9788 :
9789 : /**
9790 : \brief Fetch a raster band by index.
9791 :
9792 : The returned band remains owned by the
9793 : GDALDataset and should not be deleted by the application.
9794 :
9795 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9796 : consistent with the conventions of C/C++, i.e. starting at 0.
9797 :
9798 : @param iBand a band index between 0 and size()-1.
9799 :
9800 : @return the band, or nullptr if iBand is out of range or an error occurs.
9801 :
9802 : */
9803 :
9804 1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9805 : {
9806 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9807 : }
9808 :
9809 : /************************************************************************/
9810 : /* GDALDataset::ConstBands::Iterator::Private */
9811 : /************************************************************************/
9812 :
9813 : struct GDALDataset::ConstBands::Iterator::Private
9814 : {
9815 : const GDALRasterBand *m_poBand = nullptr;
9816 : int m_iCurBand = 0;
9817 : int m_nBandCount = 0;
9818 : const GDALDataset *m_poDS = nullptr;
9819 : };
9820 :
9821 2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9822 2 : bool bStart)
9823 2 : : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9824 : {
9825 2 : m_poPrivate->m_poDS = poDS;
9826 2 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9827 2 : if (bStart)
9828 : {
9829 1 : if (m_poPrivate->m_nBandCount)
9830 1 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9831 : }
9832 : else
9833 : {
9834 1 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9835 : }
9836 2 : }
9837 :
9838 : GDALDataset::ConstBands::Iterator::~Iterator() = default;
9839 :
9840 3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9841 : {
9842 3 : return m_poPrivate->m_poBand;
9843 : }
9844 :
9845 : GDALDataset::ConstBands::Iterator &
9846 3 : GDALDataset::ConstBands::Iterator::operator++()
9847 : {
9848 3 : m_poPrivate->m_iCurBand++;
9849 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9850 : {
9851 2 : m_poPrivate->m_poBand =
9852 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9853 : }
9854 : else
9855 : {
9856 1 : m_poPrivate->m_poBand = nullptr;
9857 : }
9858 3 : return *this;
9859 : }
9860 :
9861 4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9862 : {
9863 4 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9864 : }
9865 :
9866 : /************************************************************************/
9867 : /* GetBands() */
9868 : /************************************************************************/
9869 :
9870 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9871 : *
9872 : * This is a C++ iterator friendly version of GetRasterBand().
9873 : *
9874 : * Typical use is:
9875 : * \code{.cpp}
9876 : * for( const auto* poBand: poDS->GetConstBands() )
9877 : * {
9878 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9879 : * }
9880 : * \endcode
9881 : *
9882 : * @see GetRasterBand()
9883 : *
9884 : * @since GDAL 3.12
9885 : */
9886 4 : GDALDataset::ConstBands GDALDataset::GetBands() const
9887 : {
9888 4 : return ConstBands(this);
9889 : }
9890 :
9891 : /************************************************************************/
9892 : /* begin() */
9893 : /************************************************************************/
9894 :
9895 : /**
9896 : \brief Return beginning of band iterator.
9897 :
9898 : @since GDAL 3.12
9899 : */
9900 :
9901 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9902 : {
9903 1 : return {m_poSelf, true};
9904 : }
9905 :
9906 : /************************************************************************/
9907 : /* end() */
9908 : /************************************************************************/
9909 :
9910 : /**
9911 : \brief Return end of band iterator.
9912 :
9913 : @since GDAL 3.12
9914 : */
9915 :
9916 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9917 : {
9918 1 : return {m_poSelf, false};
9919 : }
9920 :
9921 : /************************************************************************/
9922 : /* size() */
9923 : /************************************************************************/
9924 :
9925 : /**
9926 : \brief Get the number of raster bands in this dataset.
9927 :
9928 : @return raster band count.
9929 :
9930 : @since GDAL 3.12
9931 : */
9932 :
9933 1 : size_t GDALDataset::ConstBands::size() const
9934 : {
9935 1 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9936 : }
9937 :
9938 : /************************************************************************/
9939 : /* operator[]() */
9940 : /************************************************************************/
9941 : /**
9942 : \brief Fetch a raster band by index.
9943 :
9944 : The returned band remains owned by the
9945 : GDALDataset and should not be deleted by the application.
9946 :
9947 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9948 : consistent with the conventions of C/C++, i.e. starting at 0.
9949 :
9950 : @param iBand a band index between 0 and size()-1.
9951 :
9952 : @return the band, or nullptr if iBand is out of range or an error occurs.
9953 :
9954 : @since GDAL 3.12
9955 : */
9956 :
9957 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9958 : {
9959 1 : return m_poSelf->GetRasterBand(1 + iBand);
9960 : }
9961 :
9962 : /************************************************************************/
9963 : /* operator[]() */
9964 : /************************************************************************/
9965 :
9966 : /**
9967 : \brief Fetch a raster band by index.
9968 :
9969 : The returned band remains owned by the
9970 : GDALDataset and should not be deleted by the application.
9971 :
9972 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9973 : consistent with the conventions of C/C++, i.e. starting at 0.
9974 :
9975 : @param iBand a band index between 0 and size()-1.
9976 :
9977 : @return the band, or nullptr if iBand is out of range or an error occurs.
9978 :
9979 : @since GDAL 3.12
9980 : */
9981 :
9982 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9983 : {
9984 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9985 : }
9986 :
9987 : /************************************************************************/
9988 : /* GetRootGroup() */
9989 : /************************************************************************/
9990 :
9991 : /**
9992 : \brief Return the root GDALGroup of this dataset.
9993 :
9994 : Only valid for multidimensional datasets.
9995 :
9996 : This is the same as the C function GDALDatasetGetRootGroup().
9997 :
9998 : @since GDAL 3.1
9999 : */
10000 :
10001 2951 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
10002 : {
10003 2951 : return nullptr;
10004 : }
10005 :
10006 : /************************************************************************/
10007 : /* GDALDatasetGetRootGroup() */
10008 : /************************************************************************/
10009 :
10010 : /** Return the root GDALGroup of this dataset.
10011 : *
10012 : * Only valid for multidimensional datasets.
10013 : *
10014 : * The returned value must be freed with GDALGroupRelease().
10015 : *
10016 : * This is the same as the C++ method GDALDataset::GetRootGroup().
10017 : *
10018 : * @since GDAL 3.1
10019 : */
10020 2106 : GDALGroupH GDALDatasetGetRootGroup(GDALDatasetH hDS)
10021 : {
10022 2106 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10023 2106 : auto poGroup(GDALDataset::FromHandle(hDS)->GetRootGroup());
10024 2106 : return poGroup ? new GDALGroupHS(poGroup) : nullptr;
10025 : }
10026 :
10027 : /************************************************************************/
10028 : /* GDALDatasetAsMDArray() */
10029 : /************************************************************************/
10030 :
10031 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
10032 : *
10033 : * If this dataset is not already marked as shared, it will be, so that the
10034 : * returned array holds a reference to it.
10035 : *
10036 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10037 : * returned array will have an associated indexing variable.
10038 : *
10039 : * The currently supported list of options is:
10040 : * <ul>
10041 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
10042 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
10043 : * and the last (fastest changing direction) is X
10044 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
10045 : * and the last (fastest changing direction) is Band.
10046 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
10047 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
10048 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
10049 : * "Y,X,Band" is use.
10050 : * </li>
10051 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
10052 : * item from which to build the band indexing variable.
10053 : * <ul>
10054 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
10055 : * <li>"{None}" means that no band indexing variable must be created.</li>
10056 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
10057 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
10058 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
10059 : * </ul>
10060 : * </li>
10061 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
10062 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
10063 : * Defaults to String.
10064 : * </li>
10065 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
10066 : * Defaults to "Band".
10067 : * </li>
10068 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
10069 : * </li>
10070 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
10071 : * </li>
10072 : * </ul>
10073 : *
10074 : * The returned pointer must be released with GDALMDArrayRelease().
10075 : *
10076 : * The "reverse" methods are GDALRasterBand::AsMDArray() and
10077 : * GDALDataset::AsMDArray()
10078 : *
10079 : * This is the same as the C++ method GDALDataset::AsMDArray().
10080 : *
10081 : * @param hDS Dataset handle.
10082 : * @param papszOptions Null-terminated list of strings, or nullptr.
10083 : * @return a new array, or NULL.
10084 : *
10085 : * @since GDAL 3.12
10086 : */
10087 15 : GDALMDArrayH GDALDatasetAsMDArray(GDALDatasetH hDS, CSLConstList papszOptions)
10088 : {
10089 15 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10090 30 : auto poArray(GDALDataset::FromHandle(hDS)->AsMDArray(papszOptions));
10091 15 : if (!poArray)
10092 3 : return nullptr;
10093 12 : return new GDALMDArrayHS(poArray);
10094 : }
10095 :
10096 : /************************************************************************/
10097 : /* GetRawBinaryLayout() */
10098 : /************************************************************************/
10099 :
10100 : //! @cond Doxygen_Suppress
10101 : /**
10102 : \brief Return the layout of a dataset that can be considered as a raw binary
10103 : format.
10104 :
10105 : @param sLayout Structure that will be set if the dataset is a raw binary one.
10106 : @return true if the dataset is a raw binary one.
10107 : @since GDAL 3.1
10108 : */
10109 :
10110 0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
10111 : {
10112 0 : CPL_IGNORE_RET_VAL(sLayout);
10113 0 : return false;
10114 : }
10115 :
10116 : //! @endcond
10117 :
10118 : /************************************************************************/
10119 : /* ClearStatistics() */
10120 : /************************************************************************/
10121 :
10122 : /**
10123 : \brief Clear statistics
10124 :
10125 : Only implemented for now in PAM supported datasets
10126 :
10127 : This is the same as the C function GDALDatasetClearStatistics().
10128 :
10129 : @since GDAL 3.2
10130 : */
10131 :
10132 11 : void GDALDataset::ClearStatistics()
10133 : {
10134 22 : auto poRootGroup = GetRootGroup();
10135 11 : if (poRootGroup)
10136 1 : poRootGroup->ClearStatistics();
10137 11 : }
10138 :
10139 : /************************************************************************/
10140 : /* GDALDatasetClearStatistics() */
10141 : /************************************************************************/
10142 :
10143 : /**
10144 : \brief Clear statistics
10145 :
10146 : This is the same as the C++ method GDALDataset::ClearStatistics().
10147 :
10148 : @since GDAL 3.2
10149 : */
10150 :
10151 2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
10152 : {
10153 2 : VALIDATE_POINTER0(hDS, __func__);
10154 2 : GDALDataset::FromHandle(hDS)->ClearStatistics();
10155 : }
10156 :
10157 : /************************************************************************/
10158 : /* GetFieldDomainNames() */
10159 : /************************************************************************/
10160 :
10161 : /** Returns a list of the names of all field domains stored in the dataset.
10162 : *
10163 : * @note The default implementation assumes that drivers fully populate
10164 : * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10165 : * then a specialized implementation of GetFieldDomainNames() must be
10166 : * implemented.
10167 : *
10168 : * @param papszOptions Driver specific options determining how attributes
10169 : * should be retrieved. Pass nullptr for default behavior.
10170 : *
10171 : * @return list of field domain names
10172 : * @since GDAL 3.5
10173 : */
10174 : std::vector<std::string>
10175 47 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10176 : {
10177 :
10178 47 : std::vector<std::string> names;
10179 47 : names.reserve(m_oMapFieldDomains.size());
10180 59 : for (const auto &it : m_oMapFieldDomains)
10181 : {
10182 12 : names.emplace_back(it.first);
10183 : }
10184 47 : return names;
10185 : }
10186 :
10187 : /************************************************************************/
10188 : /* GDALDatasetGetFieldDomainNames() */
10189 : /************************************************************************/
10190 :
10191 : /** Returns a list of the names of all field domains stored in the dataset.
10192 : *
10193 : * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10194 : *
10195 : * @param hDS Dataset handle.
10196 : * @param papszOptions Driver specific options determining how attributes
10197 : * should be retrieved. Pass nullptr for default behavior.
10198 : *
10199 : * @return list of field domain names, to be freed with CSLDestroy()
10200 : * @since GDAL 3.5
10201 : */
10202 40 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10203 : CSLConstList papszOptions)
10204 : {
10205 40 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10206 : auto names =
10207 80 : GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10208 80 : CPLStringList res;
10209 196 : for (const auto &name : names)
10210 : {
10211 156 : res.AddString(name.c_str());
10212 : }
10213 40 : return res.StealList();
10214 : }
10215 :
10216 : /************************************************************************/
10217 : /* GetFieldDomain() */
10218 : /************************************************************************/
10219 :
10220 : /** Get a field domain from its name.
10221 : *
10222 : * @return the field domain, or nullptr if not found.
10223 : * @since GDAL 3.3
10224 : */
10225 328 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10226 : {
10227 328 : const auto iter = m_oMapFieldDomains.find(name);
10228 328 : if (iter == m_oMapFieldDomains.end())
10229 153 : return nullptr;
10230 175 : return iter->second.get();
10231 : }
10232 :
10233 : /************************************************************************/
10234 : /* GDALDatasetGetFieldDomain() */
10235 : /************************************************************************/
10236 :
10237 : /** Get a field domain from its name.
10238 : *
10239 : * This is the same as the C++ method GDALDataset::GetFieldDomain().
10240 : *
10241 : * @param hDS Dataset handle.
10242 : * @param pszName Name of field domain.
10243 : * @return the field domain (ownership remains to the dataset), or nullptr if
10244 : * not found.
10245 : * @since GDAL 3.3
10246 : */
10247 133 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10248 : {
10249 133 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10250 133 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10251 133 : return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10252 133 : GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10253 : }
10254 :
10255 : /************************************************************************/
10256 : /* AddFieldDomain() */
10257 : /************************************************************************/
10258 :
10259 : /** Add a field domain to the dataset.
10260 : *
10261 : * Only a few drivers will support this operation, and some of them might only
10262 : * support it only for some types of field domains.
10263 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10264 : * support this operation. A dataset having at least some support for this
10265 : * operation should report the ODsCAddFieldDomain dataset capability.
10266 : *
10267 : * Anticipated failures will not be emitted through the CPLError()
10268 : * infrastructure, but will be reported in the failureReason output parameter.
10269 : *
10270 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10271 : * default implementation of GetFieldDomainNames() to work correctly, or
10272 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10273 : * implemented.
10274 : *
10275 : * @param domain The domain definition.
10276 : * @param failureReason Output parameter. Will contain an error message if
10277 : * an error occurs.
10278 : * @return true in case of success.
10279 : * @since GDAL 3.3
10280 : */
10281 0 : bool GDALDataset::AddFieldDomain(
10282 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10283 : std::string &failureReason)
10284 : {
10285 0 : failureReason = "AddFieldDomain not supported by this driver";
10286 0 : return false;
10287 : }
10288 :
10289 : /************************************************************************/
10290 : /* GDALDatasetAddFieldDomain() */
10291 : /************************************************************************/
10292 :
10293 : /** Add a field domain to the dataset.
10294 : *
10295 : * Only a few drivers will support this operation, and some of them might only
10296 : * support it only for some types of field domains.
10297 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10298 : * support this operation. A dataset having at least some support for this
10299 : * operation should report the ODsCAddFieldDomain dataset capability.
10300 : *
10301 : * Anticipated failures will not be emitted through the CPLError()
10302 : * infrastructure, but will be reported in the ppszFailureReason output
10303 : * parameter.
10304 : *
10305 : * @param hDS Dataset handle.
10306 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10307 : * the passed object is copied.
10308 : * @param ppszFailureReason Output parameter. Will contain an error message if
10309 : * an error occurs (*ppszFailureReason to be freed
10310 : * with CPLFree). May be NULL.
10311 : * @return true in case of success.
10312 : * @since GDAL 3.3
10313 : */
10314 37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10315 : char **ppszFailureReason)
10316 : {
10317 37 : VALIDATE_POINTER1(hDS, __func__, false);
10318 37 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10319 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10320 74 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10321 37 : if (poDomain == nullptr)
10322 0 : return false;
10323 37 : std::string failureReason;
10324 74 : const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10325 37 : std::move(poDomain), failureReason);
10326 37 : if (ppszFailureReason)
10327 : {
10328 37 : *ppszFailureReason =
10329 37 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10330 : }
10331 37 : return bRet;
10332 : }
10333 :
10334 : /************************************************************************/
10335 : /* DeleteFieldDomain() */
10336 : /************************************************************************/
10337 :
10338 : /** Removes a field domain from the dataset.
10339 : *
10340 : * Only a few drivers will support this operation.
10341 : *
10342 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10343 : * support this operation. A dataset having at least some support for this
10344 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10345 : *
10346 : * Anticipated failures will not be emitted through the CPLError()
10347 : * infrastructure, but will be reported in the failureReason output parameter.
10348 : *
10349 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10350 : * default implementation of GetFieldDomainNames() to work correctly, or
10351 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10352 : * implemented.
10353 : *
10354 : * @param name The domain name.
10355 : * @param failureReason Output parameter. Will contain an error message if
10356 : * an error occurs.
10357 : * @return true in case of success.
10358 : * @since GDAL 3.5
10359 : */
10360 0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10361 : std::string &failureReason)
10362 : {
10363 0 : failureReason = "DeleteFieldDomain not supported by this driver";
10364 0 : return false;
10365 : }
10366 :
10367 : /************************************************************************/
10368 : /* GDALDatasetDeleteFieldDomain() */
10369 : /************************************************************************/
10370 :
10371 : /** Removes a field domain from the dataset.
10372 : *
10373 : * Only a few drivers will support this operation.
10374 : *
10375 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10376 : * support this operation. A dataset having at least some support for this
10377 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10378 : *
10379 : * Anticipated failures will not be emitted through the CPLError()
10380 : * infrastructure, but will be reported in the ppszFailureReason output
10381 : * parameter.
10382 : *
10383 : * @param hDS Dataset handle.
10384 : * @param pszName The domain name.
10385 : * @param ppszFailureReason Output parameter. Will contain an error message if
10386 : * an error occurs (*ppszFailureReason to be freed
10387 : * with CPLFree). May be NULL.
10388 : * @return true in case of success.
10389 : * @since GDAL 3.3
10390 : */
10391 25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10392 : char **ppszFailureReason)
10393 : {
10394 25 : VALIDATE_POINTER1(hDS, __func__, false);
10395 25 : VALIDATE_POINTER1(pszName, __func__, false);
10396 25 : std::string failureReason;
10397 : const bool bRet =
10398 25 : GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10399 25 : if (ppszFailureReason)
10400 : {
10401 0 : *ppszFailureReason =
10402 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10403 : }
10404 25 : return bRet;
10405 : }
10406 :
10407 : /************************************************************************/
10408 : /* UpdateFieldDomain() */
10409 : /************************************************************************/
10410 :
10411 : /** Updates an existing field domain by replacing its definition.
10412 : *
10413 : * The existing field domain with matching name will be replaced.
10414 : *
10415 : * Only a few drivers will support this operation, and some of them might only
10416 : * support it only for some types of field domains.
10417 : * At the time of writing (GDAL 3.5), only the Memory driver
10418 : * supports this operation. A dataset having at least some support for this
10419 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10420 : *
10421 : * Anticipated failures will not be emitted through the CPLError()
10422 : * infrastructure, but will be reported in the failureReason output parameter.
10423 : *
10424 : * @param domain The domain definition.
10425 : * @param failureReason Output parameter. Will contain an error message if
10426 : * an error occurs.
10427 : * @return true in case of success.
10428 : * @since GDAL 3.5
10429 : */
10430 0 : bool GDALDataset::UpdateFieldDomain(
10431 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10432 : std::string &failureReason)
10433 : {
10434 0 : failureReason = "UpdateFieldDomain not supported by this driver";
10435 0 : return false;
10436 : }
10437 :
10438 : /************************************************************************/
10439 : /* GDALDatasetUpdateFieldDomain() */
10440 : /************************************************************************/
10441 :
10442 : /** Updates an existing field domain by replacing its definition.
10443 : *
10444 : * The existing field domain with matching name will be replaced.
10445 : *
10446 : * Only a few drivers will support this operation, and some of them might only
10447 : * support it only for some types of field domains.
10448 : * At the time of writing (GDAL 3.5), only the Memory driver
10449 : * supports this operation. A dataset having at least some support for this
10450 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10451 : *
10452 : * Anticipated failures will not be emitted through the CPLError()
10453 : * infrastructure, but will be reported in the failureReason output parameter.
10454 : *
10455 : * @param hDS Dataset handle.
10456 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10457 : * the passed object is copied.
10458 : * @param ppszFailureReason Output parameter. Will contain an error message if
10459 : * an error occurs (*ppszFailureReason to be freed
10460 : * with CPLFree). May be NULL.
10461 : * @return true in case of success.
10462 : * @since GDAL 3.5
10463 : */
10464 7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10465 : OGRFieldDomainH hFieldDomain,
10466 : char **ppszFailureReason)
10467 : {
10468 7 : VALIDATE_POINTER1(hDS, __func__, false);
10469 7 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10470 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10471 14 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10472 7 : if (poDomain == nullptr)
10473 0 : return false;
10474 7 : std::string failureReason;
10475 14 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10476 7 : std::move(poDomain), failureReason);
10477 7 : if (ppszFailureReason)
10478 : {
10479 0 : *ppszFailureReason =
10480 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10481 : }
10482 7 : return bRet;
10483 : }
10484 :
10485 : /************************************************************************/
10486 : /* GetRelationshipNames() */
10487 : /************************************************************************/
10488 :
10489 : /** Returns a list of the names of all relationships stored in the dataset.
10490 : *
10491 : * @param papszOptions Driver specific options determining how relationships
10492 : * should be retrieved. Pass nullptr for default behavior.
10493 : *
10494 : * @return list of relationship names
10495 : * @since GDAL 3.6
10496 : */
10497 : std::vector<std::string>
10498 238 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10499 : {
10500 238 : return {};
10501 : }
10502 :
10503 : /************************************************************************/
10504 : /* GDALDatasetGetRelationshipNames() */
10505 : /************************************************************************/
10506 :
10507 : /** Returns a list of the names of all relationships stored in the dataset.
10508 : *
10509 : * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10510 : *
10511 : * @param hDS Dataset handle.
10512 : * @param papszOptions Driver specific options determining how relationships
10513 : * should be retrieved. Pass nullptr for default behavior.
10514 : *
10515 : * @return list of relationship names, to be freed with CSLDestroy()
10516 : * @since GDAL 3.6
10517 : */
10518 53 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10519 : CSLConstList papszOptions)
10520 : {
10521 53 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10522 : auto names =
10523 106 : GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10524 106 : CPLStringList res;
10525 161 : for (const auto &name : names)
10526 : {
10527 108 : res.AddString(name.c_str());
10528 : }
10529 53 : return res.StealList();
10530 : }
10531 :
10532 : /************************************************************************/
10533 : /* GetRelationship() */
10534 : /************************************************************************/
10535 :
10536 : /** Get a relationship from its name.
10537 : *
10538 : * @return the relationship, or nullptr if not found.
10539 : * @since GDAL 3.6
10540 : */
10541 : const GDALRelationship *
10542 0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10543 : {
10544 0 : return nullptr;
10545 : }
10546 :
10547 : /************************************************************************/
10548 : /* GDALDatasetGetRelationship() */
10549 : /************************************************************************/
10550 :
10551 : /** Get a relationship from its name.
10552 : *
10553 : * This is the same as the C++ method GDALDataset::GetRelationship().
10554 : *
10555 : * @param hDS Dataset handle.
10556 : * @param pszName Name of relationship.
10557 : * @return the relationship (ownership remains to the dataset), or nullptr if
10558 : * not found.
10559 : * @since GDAL 3.6
10560 : */
10561 63 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10562 : const char *pszName)
10563 : {
10564 63 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10565 63 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10566 63 : return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10567 63 : GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10568 : }
10569 :
10570 : /************************************************************************/
10571 : /* AddRelationship() */
10572 : /************************************************************************/
10573 :
10574 : /** Add a relationship to the dataset.
10575 : *
10576 : * Only a few drivers will support this operation, and some of them might only
10577 : * support it only for some types of relationships.
10578 : *
10579 : * A dataset having at least some support for this
10580 : * operation should report the GDsCAddRelationship dataset capability.
10581 : *
10582 : * Anticipated failures will not be emitted through the CPLError()
10583 : * infrastructure, but will be reported in the failureReason output parameter.
10584 : *
10585 : * When adding a many-to-many relationship
10586 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10587 : * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10588 : * the driver to create an appropriately named and structured mapping table.
10589 : * Some dataset formats require particular naming conventions and field
10590 : * structures for the mapping table, and delegating the construction of the
10591 : * mapping table to the driver will avoid these pitfalls.
10592 : *
10593 : * @param relationship The relationship definition.
10594 : * @param failureReason Output parameter. Will contain an error message if
10595 : * an error occurs.
10596 : * @return true in case of success.
10597 : * @since GDAL 3.6
10598 : */
10599 0 : bool GDALDataset::AddRelationship(
10600 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10601 : std::string &failureReason)
10602 : {
10603 0 : failureReason = "AddRelationship not supported by this driver";
10604 0 : return false;
10605 : }
10606 :
10607 : /************************************************************************/
10608 : /* GDALDatasetAddRelationship() */
10609 : /************************************************************************/
10610 :
10611 : /** Add a relationship to the dataset.
10612 : *
10613 : * Only a few drivers will support this operation, and some of them might only
10614 : * support it only for some types of relationships.
10615 : *
10616 : * A dataset having at least some support for this
10617 : * operation should report the GDsCAddRelationship dataset capability.
10618 : *
10619 : * Anticipated failures will not be emitted through the CPLError()
10620 : * infrastructure, but will be reported in the failureReason output parameter.
10621 : *
10622 : * When adding a many-to-many relationship
10623 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10624 : * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10625 : * driver to create an appropriately named and structured mapping table. Some
10626 : * dataset formats require particular naming conventions and field structures
10627 : * for the mapping table, and delegating the construction of the mapping table
10628 : * to the driver will avoid these pitfalls.
10629 : *
10630 : * @param hDS Dataset handle.
10631 : * @param hRelationship The relationship definition. Contrary to the C++
10632 : * version, the passed object is copied.
10633 : * @param ppszFailureReason Output parameter. Will contain an error message if
10634 : * an error occurs (*ppszFailureReason to be freed
10635 : * with CPLFree). May be NULL.
10636 : * @return true in case of success.
10637 : * @since GDAL 3.6
10638 : */
10639 45 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10640 : GDALRelationshipH hRelationship,
10641 : char **ppszFailureReason)
10642 : {
10643 45 : VALIDATE_POINTER1(hDS, __func__, false);
10644 45 : VALIDATE_POINTER1(hRelationship, __func__, false);
10645 : std::unique_ptr<GDALRelationship> poRelationship(
10646 90 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10647 45 : std::string failureReason;
10648 90 : const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10649 45 : std::move(poRelationship), failureReason);
10650 45 : if (ppszFailureReason)
10651 : {
10652 0 : *ppszFailureReason =
10653 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10654 : }
10655 45 : return bRet;
10656 : }
10657 :
10658 : /************************************************************************/
10659 : /* DeleteRelationship() */
10660 : /************************************************************************/
10661 :
10662 : /** Removes a relationship from the dataset.
10663 : *
10664 : * Only a few drivers will support this operation.
10665 : *
10666 : * A dataset having at least some support for this
10667 : * operation should report the GDsCDeleteRelationship dataset capability.
10668 : *
10669 : * Anticipated failures will not be emitted through the CPLError()
10670 : * infrastructure, but will be reported in the failureReason output parameter.
10671 : *
10672 : * @param name The relationship name.
10673 : * @param failureReason Output parameter. Will contain an error message if
10674 : * an error occurs.
10675 : * @return true in case of success.
10676 : * @since GDAL 3.6
10677 : */
10678 0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10679 : std::string &failureReason)
10680 : {
10681 0 : failureReason = "DeleteRelationship not supported by this driver";
10682 0 : return false;
10683 : }
10684 :
10685 : /************************************************************************/
10686 : /* GDALDatasetDeleteRelationship() */
10687 : /************************************************************************/
10688 :
10689 : /** Removes a relationship from the dataset.
10690 : *
10691 : * Only a few drivers will support this operation.
10692 : *
10693 : * A dataset having at least some support for this
10694 : * operation should report the GDsCDeleteRelationship dataset capability.
10695 : *
10696 : * Anticipated failures will not be emitted through the CPLError()
10697 : * infrastructure, but will be reported in the ppszFailureReason output
10698 : * parameter.
10699 : *
10700 : * @param hDS Dataset handle.
10701 : * @param pszName The relationship name.
10702 : * @param ppszFailureReason Output parameter. Will contain an error message if
10703 : * an error occurs (*ppszFailureReason to be freed
10704 : * with CPLFree). May be NULL.
10705 : * @return true in case of success.
10706 : * @since GDAL 3.6
10707 : */
10708 8 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10709 : char **ppszFailureReason)
10710 : {
10711 8 : VALIDATE_POINTER1(hDS, __func__, false);
10712 8 : VALIDATE_POINTER1(pszName, __func__, false);
10713 8 : std::string failureReason;
10714 16 : const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10715 8 : pszName, failureReason);
10716 8 : if (ppszFailureReason)
10717 : {
10718 0 : *ppszFailureReason =
10719 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10720 : }
10721 8 : return bRet;
10722 : }
10723 :
10724 : /************************************************************************/
10725 : /* UpdateRelationship() */
10726 : /************************************************************************/
10727 :
10728 : /** Updates an existing relationship by replacing its definition.
10729 : *
10730 : * The existing relationship with matching name will be replaced.
10731 : *
10732 : * Only a few drivers will support this operation, and some of them might only
10733 : * support it only for some types of relationships.
10734 : * A dataset having at least some support for this
10735 : * operation should report the GDsCUpdateRelationship dataset capability.
10736 : *
10737 : * Anticipated failures will not be emitted through the CPLError()
10738 : * infrastructure, but will be reported in the failureReason output parameter.
10739 : *
10740 : * @param relationship The relationship definition.
10741 : * @param failureReason Output parameter. Will contain an error message if
10742 : * an error occurs.
10743 : * @return true in case of success.
10744 : * @since GDAL 3.6
10745 : */
10746 0 : bool GDALDataset::UpdateRelationship(
10747 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10748 : std::string &failureReason)
10749 : {
10750 0 : failureReason = "UpdateRelationship not supported by this driver";
10751 0 : return false;
10752 : }
10753 :
10754 : /************************************************************************/
10755 : /* GDALDatasetUpdateRelationship() */
10756 : /************************************************************************/
10757 :
10758 : /** Updates an existing relationship by replacing its definition.
10759 : *
10760 : * The existing relationship with matching name will be replaced.
10761 : *
10762 : * Only a few drivers will support this operation, and some of them might only
10763 : * support it only for some types of relationships.
10764 : * A dataset having at least some support for this
10765 : * operation should report the GDsCUpdateRelationship dataset capability.
10766 : *
10767 : * Anticipated failures will not be emitted through the CPLError()
10768 : * infrastructure, but will be reported in the failureReason output parameter.
10769 : *
10770 : * @param hDS Dataset handle.
10771 : * @param hRelationship The relationship definition. Contrary to the C++
10772 : * version, the passed object is copied.
10773 : * @param ppszFailureReason Output parameter. Will contain an error message if
10774 : * an error occurs (*ppszFailureReason to be freed
10775 : * with CPLFree). May be NULL.
10776 : * @return true in case of success.
10777 : * @since GDAL 3.5
10778 : */
10779 11 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10780 : GDALRelationshipH hRelationship,
10781 : char **ppszFailureReason)
10782 : {
10783 11 : VALIDATE_POINTER1(hDS, __func__, false);
10784 11 : VALIDATE_POINTER1(hRelationship, __func__, false);
10785 : std::unique_ptr<GDALRelationship> poRelationship(
10786 22 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10787 11 : std::string failureReason;
10788 22 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10789 11 : std::move(poRelationship), failureReason);
10790 11 : if (ppszFailureReason)
10791 : {
10792 0 : *ppszFailureReason =
10793 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10794 : }
10795 11 : return bRet;
10796 : }
10797 :
10798 : /************************************************************************/
10799 : /* GDALDatasetSetQueryLoggerFunc() */
10800 : /************************************************************************/
10801 :
10802 : /**
10803 : * Sets the SQL query logger callback.
10804 : *
10805 : * When supported by the driver, the callback will be called with
10806 : * the executed SQL text, the error message, the execution time in milliseconds,
10807 : * the number of records fetched/affected and the client status data.
10808 : *
10809 : * A value of -1 in the execution time or in the number of records indicates
10810 : * that the values are unknown.
10811 : *
10812 : * @param hDS Dataset handle.
10813 : * @param pfnQueryLoggerFunc Callback function
10814 : * @param poQueryLoggerArg Opaque client status data
10815 : * @return true in case of success.
10816 : * @since GDAL 3.7
10817 : */
10818 1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10819 : GDALQueryLoggerFunc pfnQueryLoggerFunc,
10820 : void *poQueryLoggerArg)
10821 : {
10822 1 : VALIDATE_POINTER1(hDS, __func__, false);
10823 2 : return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10824 1 : poQueryLoggerArg);
10825 : }
10826 :
10827 : //! @cond Doxygen_Suppress
10828 :
10829 : /************************************************************************/
10830 : /* SetEnableOverviews() */
10831 : /************************************************************************/
10832 :
10833 7545 : void GDALDataset::SetEnableOverviews(bool bEnable)
10834 : {
10835 7545 : if (m_poPrivate)
10836 : {
10837 7545 : m_poPrivate->m_bOverviewsEnabled = bEnable;
10838 : }
10839 7545 : }
10840 :
10841 : /************************************************************************/
10842 : /* AreOverviewsEnabled() */
10843 : /************************************************************************/
10844 :
10845 2011870 : bool GDALDataset::AreOverviewsEnabled() const
10846 : {
10847 2011870 : return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10848 : }
10849 :
10850 : /************************************************************************/
10851 : /* IsAllBands() */
10852 : /************************************************************************/
10853 :
10854 4250 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10855 : {
10856 4250 : if (nBands != nBandCount)
10857 21 : return false;
10858 4229 : if (panBandList)
10859 : {
10860 16027 : for (int i = 0; i < nBandCount; ++i)
10861 : {
10862 11892 : if (panBandList[i] != i + 1)
10863 27 : return false;
10864 : }
10865 : }
10866 4202 : return true;
10867 : }
10868 :
10869 : //! @endcond
10870 :
10871 : /************************************************************************/
10872 : /* GetCompressionFormats() */
10873 : /************************************************************************/
10874 :
10875 : /** Return the compression formats that can be natively obtained for the
10876 : * window of interest and requested bands.
10877 : *
10878 : * For example, a tiled dataset may be able to return data in a compressed
10879 : * format if the window of interest matches exactly a tile. For some formats,
10880 : * drivers may also be able to merge several tiles together (not currently
10881 : * implemented though).
10882 : *
10883 : * Each format string is a pseudo MIME type, whose first part can be passed
10884 : * as the pszFormat argument of ReadCompressedData(), with additional
10885 : * parameters specified as key=value with a semi-colon separator.
10886 : *
10887 : * The amount and types of optional parameters passed after the MIME type is
10888 : * format dependent, and driver dependent (some drivers might not be able to
10889 : * return those extra information without doing a rather costly processing).
10890 : *
10891 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10892 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10893 : * consequently "JPEG" can be passed as the pszFormat argument of
10894 : * ReadCompressedData(). For JPEG, implementations can use the
10895 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10896 : * above from a JPEG codestream.
10897 : *
10898 : * Several values might be returned. For example,
10899 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10900 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10901 : *
10902 : * In the general case this method will return an empty list.
10903 : *
10904 : * This is the same as C function GDALDatasetGetCompressionFormats().
10905 : *
10906 : * @param nXOff The pixel offset to the top left corner of the region
10907 : * of the band to be accessed. This would be zero to start from the left side.
10908 : *
10909 : * @param nYOff The line offset to the top left corner of the region
10910 : * of the band to be accessed. This would be zero to start from the top.
10911 : *
10912 : * @param nXSize The width of the region of the band to be accessed in pixels.
10913 : *
10914 : * @param nYSize The height of the region of the band to be accessed in lines.
10915 : *
10916 : * @param nBandCount the number of bands being requested.
10917 : *
10918 : * @param panBandList the list of nBandCount band numbers.
10919 : * Note band numbers are 1 based. This may be NULL to select the first
10920 : * nBandCount bands.
10921 : *
10922 : * @return a list of compatible formats (which may be empty)
10923 : *
10924 : * For example, to check if native compression format(s) are available on the
10925 : * whole image:
10926 : * \code{.cpp}
10927 : * const CPLStringList aosFormats =
10928 : * poDataset->GetCompressionFormats(0, 0,
10929 : * poDataset->GetRasterXSize(),
10930 : * poDataset->GetRasterYSize(),
10931 : * poDataset->GetRasterCount(),
10932 : * nullptr);
10933 : * for( const char* pszFormat: aosFormats )
10934 : * {
10935 : * // Remove optional parameters and just print out the MIME type.
10936 : * const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10937 : * printf("Found format %s\n, aosTokens[0]);
10938 : * }
10939 : * \endcode
10940 : *
10941 : * @since GDAL 3.7
10942 : */
10943 : CPLStringList
10944 0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10945 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10946 : CPL_UNUSED int nBandCount,
10947 : CPL_UNUSED const int *panBandList)
10948 : {
10949 0 : return CPLStringList();
10950 : }
10951 :
10952 : /************************************************************************/
10953 : /* GDALDatasetGetCompressionFormats() */
10954 : /************************************************************************/
10955 :
10956 : /** Return the compression formats that can be natively obtained for the
10957 : * window of interest and requested bands.
10958 : *
10959 : * For example, a tiled dataset may be able to return data in a compressed
10960 : * format if the window of interest matches exactly a tile. For some formats,
10961 : * drivers may also be able to merge several tiles together (not currently
10962 : * implemented though).
10963 : *
10964 : * Each format string is a pseudo MIME type, whose first part can be passed
10965 : * as the pszFormat argument of ReadCompressedData(), with additional
10966 : * parameters specified as key=value with a semi-colon separator.
10967 : *
10968 : * The amount and types of optional parameters passed after the MIME type is
10969 : * format dependent, and driver dependent (some drivers might not be able to
10970 : * return those extra information without doing a rather costly processing).
10971 : *
10972 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10973 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10974 : * consequently "JPEG" can be passed as the pszFormat argument of
10975 : * ReadCompressedData(). For JPEG, implementations can use the
10976 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10977 : * above from a JPEG codestream.
10978 : *
10979 : * Several values might be returned. For example,
10980 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10981 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10982 : *
10983 : * In the general case this method will return an empty list.
10984 : *
10985 : * This is the same as C++ method GDALDataset::GetCompressionFormats().
10986 : *
10987 : * @param hDS Dataset handle.
10988 : *
10989 : * @param nXOff The pixel offset to the top left corner of the region
10990 : * of the band to be accessed. This would be zero to start from the left side.
10991 : *
10992 : * @param nYOff The line offset to the top left corner of the region
10993 : * of the band to be accessed. This would be zero to start from the top.
10994 : *
10995 : * @param nXSize The width of the region of the band to be accessed in pixels.
10996 : *
10997 : * @param nYSize The height of the region of the band to be accessed in lines.
10998 : *
10999 : * @param nBandCount the number of bands being requested.
11000 : *
11001 : * @param panBandList the list of nBandCount band numbers.
11002 : * Note band numbers are 1 based. This may be NULL to select the first
11003 : * nBandCount bands.
11004 : *
11005 : * @return a list of compatible formats (which may be empty) that should be
11006 : * freed with CSLDestroy(), or nullptr.
11007 : *
11008 : * @since GDAL 3.7
11009 : */
11010 9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
11011 : int nXSize, int nYSize, int nBandCount,
11012 : const int *panBandList)
11013 : {
11014 9 : VALIDATE_POINTER1(hDS, __func__, nullptr);
11015 9 : return GDALDataset::FromHandle(hDS)
11016 9 : ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
11017 9 : panBandList)
11018 9 : .StealList();
11019 : }
11020 :
11021 : /************************************************************************/
11022 : /* ReadCompressedData() */
11023 : /************************************************************************/
11024 :
11025 : /** Return the compressed content that can be natively obtained for the
11026 : * window of interest and requested bands.
11027 : *
11028 : * For example, a tiled dataset may be able to return data in compressed format
11029 : * if the window of interest matches exactly a tile. For some formats, drivers
11030 : * may also be example to merge several tiles together (not currently
11031 : * implemented though).
11032 : *
11033 : * The implementation should make sure that the content returned forms a valid
11034 : * standalone file. For example, for the GeoTIFF implementation of this method,
11035 : * when extracting a JPEG tile, the method will automatically add the content
11036 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11037 : * TIFF JpegTables tag, and not in tile data itself.
11038 : *
11039 : * In the general case this method will return CE_Failure.
11040 : *
11041 : * This is the same as C function GDALDatasetReadCompressedData().
11042 : *
11043 : * @param pszFormat Requested compression format (e.g. "JPEG",
11044 : * "WEBP", "JXL"). This is the MIME type of one of the values
11045 : * returned by GetCompressionFormats(). The format string is designed to
11046 : * potentially include at a later point key=value optional parameters separated
11047 : * by a semi-colon character. At time of writing, none are implemented.
11048 : * ReadCompressedData() implementations should verify optional parameters and
11049 : * return CE_Failure if they cannot support one of them.
11050 : *
11051 : * @param nXOff The pixel offset to the top left corner of the region
11052 : * of the band to be accessed. This would be zero to start from the left side.
11053 : *
11054 : * @param nYOff The line offset to the top left corner of the region
11055 : * of the band to be accessed. This would be zero to start from the top.
11056 : *
11057 : * @param nXSize The width of the region of the band to be accessed in pixels.
11058 : *
11059 : * @param nYSize The height of the region of the band to be accessed in lines.
11060 : *
11061 : * @param nBandCount the number of bands being requested.
11062 : *
11063 : * @param panBandList the list of nBandCount band numbers.
11064 : * Note band numbers are 1 based. This may be NULL to select the first
11065 : * nBandCount bands.
11066 : *
11067 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11068 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11069 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11070 : * buffer will be filled with the compressed data, provided that pnBufferSize
11071 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11072 : * of *ppBuffer, is sufficiently large to hold the data.
11073 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11074 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11075 : * free it with VSIFree().
11076 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11077 : * but *pnBufferSize will be updated with an upper bound of the size that would
11078 : * be necessary to hold it (if pnBufferSize != nullptr).
11079 : *
11080 : * @param pnBufferSize Output buffer size, or nullptr.
11081 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11082 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11083 : * method is successful, *pnBufferSize will be updated with the actual size
11084 : * used.
11085 : *
11086 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11087 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11088 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11089 : * *ppszDetailedFormat might contain strings like
11090 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11091 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11092 : * The string will contain at least as much information as what
11093 : * GetCompressionFormats() returns, and potentially more when
11094 : * ppBuffer != nullptr.
11095 : *
11096 : * @return CE_None in case of success, CE_Failure otherwise.
11097 : *
11098 : * For example, to request JPEG content on the whole image and let GDAL deal
11099 : * with the buffer allocation.
11100 : * \code{.cpp}
11101 : * void* pBuffer = nullptr;
11102 : * size_t nBufferSize = 0;
11103 : * CPLErr eErr =
11104 : * poDataset->ReadCompressedData("JPEG",
11105 : * 0, 0,
11106 : * poDataset->GetRasterXSize(),
11107 : * poDataset->GetRasterYSize(),
11108 : * poDataset->GetRasterCount(),
11109 : * nullptr, // panBandList
11110 : * &pBuffer,
11111 : * &nBufferSize,
11112 : * nullptr // ppszDetailedFormat
11113 : * );
11114 : * if (eErr == CE_None)
11115 : * {
11116 : * CPLAssert(pBuffer != nullptr);
11117 : * CPLAssert(nBufferSize > 0);
11118 : * VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11119 : * if (fp)
11120 : * {
11121 : * VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11122 : * VSIFCloseL(fp);
11123 : * }
11124 : * VSIFree(pBuffer);
11125 : * }
11126 : * \endcode
11127 : *
11128 : * Or to manage the buffer allocation on your side:
11129 : * \code{.cpp}
11130 : * size_t nUpperBoundBufferSize = 0;
11131 : * CPLErr eErr =
11132 : * poDataset->ReadCompressedData("JPEG",
11133 : * 0, 0,
11134 : * poDataset->GetRasterXSize(),
11135 : * poDataset->GetRasterYSize(),
11136 : * poDataset->GetRasterCount(),
11137 : * nullptr, // panBandList
11138 : * nullptr, // ppBuffer,
11139 : * &nUpperBoundBufferSize,
11140 : * nullptr // ppszDetailedFormat
11141 : * );
11142 : * if (eErr == CE_None)
11143 : * {
11144 : * std::vector<uint8_t> myBuffer;
11145 : * myBuffer.resize(nUpperBoundBufferSize);
11146 : * void* pBuffer = myBuffer.data();
11147 : * size_t nActualSize = nUpperBoundBufferSize;
11148 : * char* pszDetailedFormat = nullptr;
11149 : * // We also request detailed format, but we could have passed it to
11150 : * // nullptr as well.
11151 : * eErr =
11152 : * poDataset->ReadCompressedData("JPEG",
11153 : * 0, 0,
11154 : * poDataset->GetRasterXSize(),
11155 : * poDataset->GetRasterYSize(),
11156 : * poDataset->GetRasterCount(),
11157 : * nullptr, // panBandList
11158 : * &pBuffer,
11159 : * &nActualSize,
11160 : * &pszDetailedFormat);
11161 : * if (eErr == CE_None)
11162 : * {
11163 : * CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11164 : * CPLAssert(nActualSize <= nUpperBoundBufferSize);
11165 : * myBuffer.resize(nActualSize);
11166 : * // do something useful
11167 : * VSIFree(pszDetailedFormat);
11168 : * }
11169 : * }
11170 : * \endcode
11171 : *
11172 : * @since GDAL 3.7
11173 : */
11174 450 : CPLErr GDALDataset::ReadCompressedData(
11175 : CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11176 : CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11177 : CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11178 : CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11179 : CPL_UNUSED char **ppszDetailedFormat)
11180 : {
11181 450 : return CE_Failure;
11182 : }
11183 :
11184 : /************************************************************************/
11185 : /* GDALDatasetReadCompressedData() */
11186 : /************************************************************************/
11187 :
11188 : /** Return the compressed content that can be natively obtained for the
11189 : * window of interest and requested bands.
11190 : *
11191 : * For example, a tiled dataset may be able to return data in compressed format
11192 : * if the window of interest matches exactly a tile. For some formats, drivers
11193 : * may also be example to merge several tiles together (not currently
11194 : * implemented though).
11195 : *
11196 : * The implementation should make sure that the content returned forms a valid
11197 : * standalone file. For example, for the GeoTIFF implementation of this method,
11198 : * when extracting a JPEG tile, the method will automatically adds the content
11199 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11200 : * TIFF JpegTables tag, and not in tile data itself.
11201 : *
11202 : * In the general case this method will return CE_Failure.
11203 : *
11204 : * This is the same as C++ method GDALDataset:ReadCompressedData().
11205 : *
11206 : * @param hDS Dataset handle.
11207 : *
11208 : * @param pszFormat Requested compression format (e.g. "JPEG",
11209 : * "WEBP", "JXL"). This is the MIME type of one of the values
11210 : * returned by GetCompressionFormats(). The format string is designed to
11211 : * potentially include at a later point key=value optional parameters separated
11212 : * by a semi-colon character. At time of writing, none are implemented.
11213 : * ReadCompressedData() implementations should verify optional parameters and
11214 : * return CE_Failure if they cannot support one of them.
11215 : *
11216 : * @param nXOff The pixel offset to the top left corner of the region
11217 : * of the band to be accessed. This would be zero to start from the left side.
11218 : *
11219 : * @param nYOff The line offset to the top left corner of the region
11220 : * of the band to be accessed. This would be zero to start from the top.
11221 : *
11222 : * @param nXSize The width of the region of the band to be accessed in pixels.
11223 : *
11224 : * @param nYSize The height of the region of the band to be accessed in lines.
11225 : *
11226 : * @param nBandCount the number of bands being requested.
11227 : *
11228 : * @param panBandList the list of nBandCount band numbers.
11229 : * Note band numbers are 1 based. This may be NULL to select the first
11230 : * nBandCount bands.
11231 : *
11232 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11233 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11234 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11235 : * buffer will be filled with the compressed data, provided that pnBufferSize
11236 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11237 : * of *ppBuffer, is sufficiently large to hold the data.
11238 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11239 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11240 : * free it with VSIFree().
11241 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11242 : * but *pnBufferSize will be updated with an upper bound of the size that would
11243 : * be necessary to hold it (if pnBufferSize != nullptr).
11244 : *
11245 : * @param pnBufferSize Output buffer size, or nullptr.
11246 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11247 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11248 : * method is successful, *pnBufferSize will be updated with the actual size
11249 : * used.
11250 : *
11251 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11252 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11253 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11254 : * *ppszDetailedFormat might contain strings like
11255 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11256 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11257 : * The string will contain at least as much information as what
11258 : * GetCompressionFormats() returns, and potentially more when
11259 : * ppBuffer != nullptr.
11260 : *
11261 : * @return CE_None in case of success, CE_Failure otherwise.
11262 : *
11263 : * @since GDAL 3.7
11264 : */
11265 28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11266 : int nXOff, int nYOff, int nXSize,
11267 : int nYSize, int nBandCount,
11268 : const int *panBandList, void **ppBuffer,
11269 : size_t *pnBufferSize,
11270 : char **ppszDetailedFormat)
11271 : {
11272 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11273 56 : return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11274 : pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11275 28 : ppBuffer, pnBufferSize, ppszDetailedFormat);
11276 : }
11277 :
11278 : /************************************************************************/
11279 : /* CanBeCloned() */
11280 : /************************************************************************/
11281 :
11282 : //! @cond Doxygen_Suppress
11283 :
11284 : /** This method is called by GDALThreadSafeDataset::Create() to determine if
11285 : * it is possible to create a thread-safe wrapper for a dataset, which involves
11286 : * the ability to Clone() it.
11287 : *
11288 : * Implementations of this method must be thread-safe.
11289 : *
11290 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11291 : * expressing the intended use for thread-safety.
11292 : * Currently, the only valid scope is in the base
11293 : * implementation is GDAL_OF_RASTER.
11294 : * @param bCanShareState Determines if cloned datasets are allowed to share
11295 : * state with the dataset they have been cloned from.
11296 : * If set to true, the dataset from which they have been
11297 : * cloned from must remain opened during the lifetime of
11298 : * its clones.
11299 : * @return true if the Clone() method is expected to succeed with the same values
11300 : * of nScopeFlags and bCanShareState.
11301 : */
11302 151 : bool GDALDataset::CanBeCloned(int nScopeFlags,
11303 : [[maybe_unused]] bool bCanShareState) const
11304 : {
11305 151 : return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11306 : }
11307 :
11308 : //! @endcond
11309 :
11310 : /************************************************************************/
11311 : /* Clone() */
11312 : /************************************************************************/
11313 :
11314 : //! @cond Doxygen_Suppress
11315 :
11316 : /** This method "clones" the current dataset, that is it returns a new instance
11317 : * that is opened on the same underlying "file".
11318 : *
11319 : * The base implementation uses GDALDataset::Open() to re-open the dataset.
11320 : * The MEM driver has a specialized implementation that returns a new instance,
11321 : * but which shares the same memory buffer as this.
11322 : *
11323 : * Implementations of this method must be thread-safe.
11324 : *
11325 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11326 : * expressing the intended use for thread-safety.
11327 : * Currently, the only valid scope is in the base
11328 : * implementation is GDAL_OF_RASTER.
11329 : * @param bCanShareState Determines if cloned datasets are allowed to share
11330 : * state with the dataset they have been cloned from.
11331 : * If set to true, the dataset from which they have been
11332 : * cloned from must remain opened during the lifetime of
11333 : * its clones.
11334 : * @return a new instance, or nullptr in case of error.
11335 : */
11336 : std::unique_ptr<GDALDataset>
11337 2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11338 : {
11339 4102 : CPLStringList aosAllowedDrivers;
11340 2051 : if (poDriver)
11341 2051 : aosAllowedDrivers.AddString(poDriver->GetDescription());
11342 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11343 2051 : GetDescription(),
11344 2051 : nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11345 4102 : aosAllowedDrivers.List(), papszOpenOptions));
11346 : }
11347 :
11348 : //! @endcond
11349 :
11350 : /************************************************************************/
11351 : /* GeolocationToPixelLine() */
11352 : /************************************************************************/
11353 :
11354 : /** Transform georeferenced coordinates to pixel/line coordinates.
11355 : *
11356 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11357 : * must be in the "natural" SRS of the dataset, that is the one returned by
11358 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11359 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11360 : * array (generally WGS 84) if there is a geolocation array.
11361 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11362 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11363 : * be a easting, and dfGeolocY a northing.
11364 : *
11365 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11366 : * expressed in that CRS, and that tuple must be conformant with the
11367 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11368 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11369 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11370 : * before calling this method, and in that case, dfGeolocX must be a longitude
11371 : * or an easting value, and dfGeolocX a latitude or a northing value.
11372 : *
11373 : * This method uses GDALCreateGenImgProjTransformer2() underneath.
11374 : *
11375 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11376 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11377 : * where interpolation should be done.
11378 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11379 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11380 : * where interpolation should be done.
11381 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11382 : * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11383 : * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11384 : * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11385 : *
11386 : * @return CE_None on success, or an error code on failure.
11387 : * @since GDAL 3.11
11388 : */
11389 :
11390 : CPLErr
11391 15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11392 : const OGRSpatialReference *poSRS,
11393 : double *pdfPixel, double *pdfLine,
11394 : CSLConstList papszTransformerOptions) const
11395 : {
11396 30 : CPLStringList aosTO(papszTransformerOptions);
11397 :
11398 15 : if (poSRS)
11399 : {
11400 4 : const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11401 8 : const std::string osWKT = poSRS->exportToWkt(apszOptions);
11402 4 : aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11403 4 : const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11404 4 : if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11405 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11406 1 : "TRADITIONAL_GIS_ORDER");
11407 3 : else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11408 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11409 1 : "AUTHORITY_COMPLIANT");
11410 : else
11411 : {
11412 2 : const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11413 4 : std::string osVal;
11414 6 : for (int v : anValues)
11415 : {
11416 4 : if (!osVal.empty())
11417 2 : osVal += ',';
11418 4 : osVal += std::to_string(v);
11419 : }
11420 : aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11421 2 : osVal.c_str());
11422 : }
11423 : }
11424 :
11425 15 : auto hTransformer = GDALCreateGenImgProjTransformer2(
11426 : GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11427 15 : aosTO.List());
11428 15 : if (hTransformer == nullptr)
11429 : {
11430 1 : return CE_Failure;
11431 : }
11432 :
11433 14 : double z = 0;
11434 14 : int bSuccess = 0;
11435 14 : GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11436 : &bSuccess);
11437 14 : GDALDestroyTransformer(hTransformer);
11438 14 : if (bSuccess)
11439 : {
11440 14 : if (pdfPixel)
11441 14 : *pdfPixel = dfGeolocX;
11442 14 : if (pdfLine)
11443 14 : *pdfLine = dfGeolocY;
11444 14 : return CE_None;
11445 : }
11446 : else
11447 : {
11448 0 : return CE_Failure;
11449 : }
11450 : }
11451 :
11452 : /************************************************************************/
11453 : /* GDALDatasetGeolocationToPixelLine() */
11454 : /************************************************************************/
11455 :
11456 : /** Transform georeferenced coordinates to pixel/line coordinates.
11457 : *
11458 : * @see GDALDataset::GeolocationToPixelLine()
11459 : * @since GDAL 3.11
11460 : */
11461 :
11462 0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11463 : double dfGeolocY,
11464 : OGRSpatialReferenceH hSRS,
11465 : double *pdfPixel, double *pdfLine,
11466 : CSLConstList papszTransformerOptions)
11467 : {
11468 0 : VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11469 :
11470 0 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11471 0 : return poDS->GeolocationToPixelLine(
11472 0 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11473 0 : pdfLine, papszTransformerOptions);
11474 : }
11475 :
11476 : /************************************************************************/
11477 : /* GetExtent() */
11478 : /************************************************************************/
11479 :
11480 : /** Return extent of dataset in specified CRS.
11481 : *
11482 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11483 : *
11484 : * For rasters, the base implementation of this method only succeeds if
11485 : * GetGeoTransform() and GetSpatialRef() succeed.
11486 : * For vectors, the base implementation of this method iterates over layers
11487 : * and call their OGRLayer::GetExtent() method.
11488 : *
11489 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11490 : * time of this method is fast.
11491 : *
11492 : * This is the same as C function GDALGetExtent()
11493 : *
11494 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11495 : * @param poCRS CRS in which to express the extent. If not specified, this will
11496 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11497 : * @return CE_None in case of success, CE_Failure otherwise
11498 : * @since GDAL 3.12
11499 : */
11500 :
11501 468 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11502 : const OGRSpatialReference *poCRS) const
11503 : {
11504 468 : const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11505 468 : int nLayerCount = 0;
11506 468 : if (!poThisCRS)
11507 : {
11508 93 : nLayerCount = GetLayerCount();
11509 93 : if (nLayerCount >= 1)
11510 : {
11511 3 : if (auto poLayer = GetLayer(0))
11512 3 : poThisCRS = poLayer->GetSpatialRef();
11513 : }
11514 : }
11515 468 : if (!poCRS)
11516 246 : poCRS = poThisCRS;
11517 222 : else if (!poThisCRS)
11518 3 : return CE_Failure;
11519 :
11520 465 : *psExtent = OGREnvelope();
11521 :
11522 465 : GDALGeoTransform gt;
11523 465 : auto poThisDS = const_cast<GDALDataset *>(this);
11524 465 : const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11525 465 : if (bHasGT)
11526 : {
11527 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
11528 460 : if (poCRS)
11529 : {
11530 375 : poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11531 : }
11532 :
11533 460 : constexpr int DENSIFY_POINT_COUNT = 21;
11534 460 : double dfULX = gt.xorig;
11535 460 : double dfULY = gt.yorig;
11536 460 : double dfURX = 0, dfURY = 0;
11537 460 : gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11538 460 : double dfLLX = 0, dfLLY = 0;
11539 460 : gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11540 460 : double dfLRX = 0, dfLRY = 0;
11541 460 : gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11542 460 : const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11543 460 : const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11544 460 : const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11545 460 : const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11546 460 : if (poCT)
11547 : {
11548 373 : OGREnvelope sEnvTmp;
11549 746 : if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11550 : &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11551 373 : &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11552 : {
11553 0 : return CE_Failure;
11554 : }
11555 373 : *psExtent = sEnvTmp;
11556 : }
11557 : else
11558 : {
11559 87 : psExtent->MinX = xmin;
11560 87 : psExtent->MinY = ymin;
11561 87 : psExtent->MaxX = xmax;
11562 87 : psExtent->MaxY = ymax;
11563 : }
11564 : }
11565 :
11566 465 : if (nLayerCount > 0)
11567 : {
11568 6 : for (auto &&poLayer : poThisDS->GetLayers())
11569 : {
11570 3 : auto poLayerCRS = poLayer->GetSpatialRef();
11571 3 : if (poLayerCRS)
11572 : {
11573 3 : OGREnvelope sLayerExtent;
11574 3 : if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11575 : {
11576 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11577 6 : OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11578 3 : if (poCT)
11579 : {
11580 3 : constexpr int DENSIFY_POINT_COUNT = 21;
11581 3 : OGREnvelope sEnvTmp;
11582 3 : if (poCT->TransformBounds(
11583 : sLayerExtent.MinX, sLayerExtent.MinY,
11584 : sLayerExtent.MaxX, sLayerExtent.MaxY,
11585 : &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11586 : &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11587 3 : DENSIFY_POINT_COUNT))
11588 : {
11589 3 : psExtent->Merge(sEnvTmp);
11590 : }
11591 : }
11592 : }
11593 : }
11594 : }
11595 : }
11596 :
11597 465 : return psExtent->IsInit() ? CE_None : CE_Failure;
11598 : }
11599 :
11600 : /************************************************************************/
11601 : /* GDALGetExtent() */
11602 : /************************************************************************/
11603 :
11604 : /** Return extent of dataset in specified CRS.
11605 : *
11606 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11607 : *
11608 : * For rasters, the base implementation of this method only succeeds if
11609 : * GetGeoTransform() and GetSpatialRef() succeed.
11610 : * For vectors, the base implementation of this method iterates over layers
11611 : * and call their OGRLayer::GetExtent() method.
11612 : *
11613 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11614 : * time of this method is fast.
11615 : *
11616 : * This is the same as C++ method GDALDataset::GetExtent()
11617 : *
11618 : * @param hDS Dataset handle. Must NOT be null.
11619 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11620 : * @param hCRS CRS in which to express the extent. If not specified, this will
11621 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11622 : * @return extent in poCRS (valid only if IsInit() method returns true)
11623 : * @since GDAL 3.12
11624 : */
11625 :
11626 28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11627 : OGRSpatialReferenceH hCRS)
11628 : {
11629 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11630 28 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11631 56 : return GDALDataset::FromHandle(hDS)->GetExtent(
11632 28 : psExtent, OGRSpatialReference::FromHandle(hCRS));
11633 : }
11634 :
11635 : /************************************************************************/
11636 : /* GetExtentWGS84LongLat() */
11637 : /************************************************************************/
11638 :
11639 : /** Return extent of dataset in WGS84 longitude/latitude
11640 : *
11641 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11642 : *
11643 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11644 : * time of this method is fast.
11645 : *
11646 : * This is the same as C function GDALGetExtentWGS84LongLat()
11647 : *
11648 : * @return extent (valid only if IsInit() method returns true)
11649 : * @since GDAL 3.12
11650 : */
11651 :
11652 220 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11653 : {
11654 440 : OGRSpatialReference oSRS_WGS84;
11655 220 : oSRS_WGS84.SetFromUserInput("WGS84");
11656 220 : oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11657 440 : return GetExtent(psExtent, &oSRS_WGS84);
11658 : }
11659 :
11660 : /************************************************************************/
11661 : /* GDALGetExtentWGS84LongLat() */
11662 : /************************************************************************/
11663 :
11664 : /** Return extent of dataset in WGS84 longitude/latitude
11665 : *
11666 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11667 : *
11668 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11669 : * time of this method is fast.
11670 : *
11671 : * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11672 : *
11673 : * @param hDS Dataset handle. Must NOT be null.
11674 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11675 : * @return extent (valid only if IsInit() method returns true)
11676 : * @since GDAL 3.12
11677 : */
11678 :
11679 5 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11680 : {
11681 5 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11682 5 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11683 5 : return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11684 : }
11685 :
11686 : /************************************************************************/
11687 : /* ReportUpdateNotSupportedByDriver() */
11688 : /************************************************************************/
11689 :
11690 : //! @cond Doxygen_Suppress
11691 :
11692 : /* static */
11693 1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11694 : {
11695 1 : CPLError(CE_Failure, CPLE_NotSupported,
11696 : "The %s driver does not support update access to existing "
11697 : "datasets.",
11698 : pszDriverName);
11699 1 : }
11700 :
11701 : //! @endcond
11702 :
11703 : /************************************************************************/
11704 : /* BuildFilename() */
11705 : /************************************************************************/
11706 :
11707 : /** Generates a filename, potentially relative to another one.
11708 : *
11709 : * Given the path to a reference directory, and a path to a file
11710 : * referenced from it, build a path to the file that the current application
11711 : * can use. If the file path is already absolute, rather than relative, or if
11712 : * bRelativeToReferencePath is false, then the filename of interest will be
11713 : * returned unaltered.
11714 : *
11715 : * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11716 : * into account the subdataset syntax.
11717 : *
11718 : * Examples:
11719 : * \code{.cpp}
11720 : * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11721 : * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11722 : * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11723 : * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11724 : * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11725 : * \endcode
11726 : *
11727 : * @param pszFilename Filename of interest.
11728 : * @param pszReferencePath Path to a reference directory.
11729 : * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11730 : * relative to pszReferencePath
11731 : * @since 3.11
11732 : */
11733 :
11734 : /* static */
11735 104262 : std::string GDALDataset::BuildFilename(const char *pszFilename,
11736 : const char *pszReferencePath,
11737 : bool bRelativeToReferencePath)
11738 : {
11739 104262 : std::string osSrcDSName;
11740 104262 : if (pszReferencePath != nullptr && bRelativeToReferencePath)
11741 : {
11742 : // Try subdatasetinfo API first
11743 : // Note: this will become the only branch when subdatasetinfo will become
11744 : // available for NITF_IM, RASTERLITE and TILEDB
11745 2620 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11746 2620 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11747 : {
11748 8 : auto path{oSubDSInfo->GetPathComponent()};
11749 12 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
11750 8 : CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11751 4 : .c_str());
11752 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
11753 : }
11754 : else
11755 : {
11756 2616 : bool bDone = false;
11757 15681 : for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11758 : {
11759 13068 : CPLString osPrefix(pszSyntax);
11760 13068 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11761 13068 : if (pszSyntax[osPrefix.size()] == '"')
11762 2613 : osPrefix += '"';
11763 13068 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11764 : {
11765 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11766 : {
11767 3 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11768 : // CSV:z:/foo.xyz
11769 3 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11770 0 : pszLastPart - pszFilename >= 3 &&
11771 0 : pszLastPart[-3] == ':')
11772 : {
11773 0 : pszLastPart -= 2;
11774 : }
11775 3 : CPLString osPrefixFilename = pszFilename;
11776 3 : osPrefixFilename.resize(pszLastPart - pszFilename);
11777 6 : osSrcDSName = osPrefixFilename +
11778 6 : CPLProjectRelativeFilenameSafe(
11779 3 : pszReferencePath, pszLastPart);
11780 3 : bDone = true;
11781 : }
11782 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11783 : "{FILENAME}"))
11784 : {
11785 0 : CPLString osFilename(pszFilename + osPrefix.size());
11786 0 : size_t nPos = 0;
11787 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11788 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
11789 0 : nPos = 2;
11790 0 : nPos = osFilename.find(
11791 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11792 : nPos);
11793 0 : if (nPos != std::string::npos)
11794 : {
11795 0 : const CPLString osSuffix = osFilename.substr(nPos);
11796 0 : osFilename.resize(nPos);
11797 0 : osSrcDSName = osPrefix +
11798 0 : CPLProjectRelativeFilenameSafe(
11799 0 : pszReferencePath, osFilename) +
11800 0 : osSuffix;
11801 0 : bDone = true;
11802 : }
11803 : }
11804 3 : break;
11805 : }
11806 : }
11807 2616 : if (!bDone)
11808 : {
11809 2613 : std::string osReferencePath = pszReferencePath;
11810 2613 : if (!CPLIsFilenameRelative(pszReferencePath))
11811 : {
11812 : // Simplify path by replacing "foo/a/../b" with "foo/b"
11813 2320 : while (STARTS_WITH(pszFilename, "../"))
11814 : {
11815 : osReferencePath =
11816 5 : CPLGetPathSafe(osReferencePath.c_str());
11817 5 : pszFilename += strlen("../");
11818 : }
11819 : }
11820 :
11821 5226 : osSrcDSName = CPLProjectRelativeFilenameSafe(
11822 2613 : osReferencePath.c_str(), pszFilename);
11823 : }
11824 2620 : }
11825 : }
11826 : else
11827 : {
11828 101642 : osSrcDSName = pszFilename;
11829 : }
11830 104262 : return osSrcDSName;
11831 : }
11832 :
11833 : /************************************************************************/
11834 : /* GDALMDArrayFromDataset */
11835 : /************************************************************************/
11836 :
11837 : class GDALMDArrayFromDataset final : public GDALMDArray
11838 : {
11839 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11840 :
11841 : GDALDataset *const m_poDS;
11842 : const GDALExtendedDataType m_dt;
11843 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11844 : std::string m_osUnit{};
11845 : std::vector<GByte> m_abyNoData{};
11846 : std::shared_ptr<GDALMDArray> m_varX{};
11847 : std::shared_ptr<GDALMDArray> m_varY{};
11848 : std::shared_ptr<GDALMDArray> m_varBand{};
11849 : const std::string m_osFilename;
11850 : const CPLStringList m_aosOptions;
11851 : int m_iBandDim = 0;
11852 : int m_iYDim = 1;
11853 : int m_iXDim = 2;
11854 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11855 :
11856 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11857 : const size_t *count, const GInt64 *arrayStep,
11858 : const GPtrDiff_t *bufferStride,
11859 : const GDALExtendedDataType &bufferDataType,
11860 : void *pBuffer) const;
11861 :
11862 : protected:
11863 17 : GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11864 34 : : GDALAbstractMDArray(std::string(),
11865 34 : std::string(poDS->GetDescription())),
11866 34 : GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11867 : m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11868 : poDS->GetRasterBand(1)->GetRasterDataType())),
11869 85 : m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11870 : {
11871 17 : m_poDS->Reference();
11872 :
11873 17 : const int nBandCount = poDS->GetRasterCount();
11874 47 : for (int i = 1; i <= nBandCount; ++i)
11875 : {
11876 30 : const auto poBand = poDS->GetRasterBand(i);
11877 30 : if (i == 1)
11878 17 : m_osUnit = poBand->GetUnitType();
11879 13 : else if (m_osUnit != poBand->GetUnitType())
11880 7 : m_osUnit.clear();
11881 :
11882 60 : std::vector<GByte> abyNoData;
11883 30 : int bHasNoData = false;
11884 30 : switch (poBand->GetRasterDataType())
11885 : {
11886 0 : case GDT_Int64:
11887 : {
11888 : const auto nNoData =
11889 0 : poBand->GetNoDataValueAsInt64(&bHasNoData);
11890 0 : if (bHasNoData)
11891 : {
11892 0 : abyNoData.resize(m_dt.GetSize());
11893 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11894 : m_dt.GetNumericDataType(), 0, 1);
11895 : }
11896 0 : break;
11897 : }
11898 :
11899 0 : case GDT_UInt64:
11900 : {
11901 : const auto nNoData =
11902 0 : poBand->GetNoDataValueAsUInt64(&bHasNoData);
11903 0 : if (bHasNoData)
11904 : {
11905 0 : abyNoData.resize(m_dt.GetSize());
11906 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11907 : m_dt.GetNumericDataType(), 0, 1);
11908 : }
11909 0 : break;
11910 : }
11911 :
11912 30 : default:
11913 : {
11914 30 : const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11915 30 : if (bHasNoData)
11916 : {
11917 11 : abyNoData.resize(m_dt.GetSize());
11918 22 : GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11919 11 : &abyNoData[0],
11920 : m_dt.GetNumericDataType(), 0, 1);
11921 : }
11922 30 : break;
11923 : }
11924 : }
11925 :
11926 30 : if (i == 1)
11927 17 : m_abyNoData = std::move(abyNoData);
11928 13 : else if (m_abyNoData != abyNoData)
11929 7 : m_abyNoData.clear();
11930 : }
11931 :
11932 17 : const int nXSize = poDS->GetRasterXSize();
11933 17 : const int nYSize = poDS->GetRasterYSize();
11934 :
11935 17 : auto poSRS = poDS->GetSpatialRef();
11936 34 : std::string osTypeY;
11937 34 : std::string osTypeX;
11938 34 : std::string osDirectionY;
11939 34 : std::string osDirectionX;
11940 17 : if (poSRS && poSRS->GetAxesCount() == 2)
11941 : {
11942 8 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11943 8 : OGRAxisOrientation eOrientation1 = OAO_Other;
11944 8 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11945 8 : OGRAxisOrientation eOrientation2 = OAO_Other;
11946 8 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11947 8 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11948 : {
11949 6 : if (mapping == std::vector<int>{1, 2})
11950 : {
11951 6 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11952 6 : osDirectionY = "NORTH";
11953 6 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11954 6 : osDirectionX = "EAST";
11955 : }
11956 : }
11957 2 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11958 : {
11959 2 : if (mapping == std::vector<int>{2, 1})
11960 : {
11961 2 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11962 2 : osDirectionY = "NORTH";
11963 2 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11964 2 : osDirectionX = "EAST";
11965 : }
11966 : }
11967 : }
11968 :
11969 47 : const bool bBandYX = [papszOptions, poDS, nBandCount]()
11970 : {
11971 : const char *pszDimOrder =
11972 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11973 17 : if (EQUAL(pszDimOrder, "AUTO"))
11974 : {
11975 : const char *pszInterleave =
11976 15 : poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11977 24 : return nBandCount == 1 || !pszInterleave ||
11978 24 : !EQUAL(pszInterleave, "PIXEL");
11979 : }
11980 : else
11981 : {
11982 2 : return EQUAL(pszDimOrder, "BAND,Y,X");
11983 : }
11984 17 : }();
11985 : const char *const pszBandDimName =
11986 17 : CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11987 : auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11988 51 : "/", pszBandDimName, std::string(), std::string(), nBandCount);
11989 : const char *const pszYDimName =
11990 17 : CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11991 : auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11992 34 : "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11993 : const char *const pszXDimName =
11994 17 : CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11995 : auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11996 34 : "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11997 :
11998 17 : const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11999 : papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
12000 17 : if (EQUAL(pszBandIndexingVarItem, "{Description}"))
12001 : {
12002 : const auto oIndexingVarType =
12003 22 : GDALExtendedDataType::CreateString(strlen("Band 65535"));
12004 11 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12005 44 : {poBandDim}, oIndexingVarType);
12006 11 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12007 29 : for (int i = 0; i < nBandCount; ++i)
12008 : {
12009 : const char *pszDesc =
12010 18 : poDS->GetRasterBand(i + 1)->GetDescription();
12011 : const std::string osBandName =
12012 36 : pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
12013 18 : const char *pszBandName = osBandName.c_str();
12014 18 : const char *const apszBandVal[] = {pszBandName};
12015 18 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12016 18 : const size_t anCount[] = {1};
12017 18 : const GInt64 arrayStep[] = {1};
12018 18 : const GPtrDiff_t anBufferStride[] = {1};
12019 18 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12020 : oIndexingVarType, apszBandVal);
12021 : }
12022 11 : m_varBand = std::move(poBandVar);
12023 11 : poBandDim->SetIndexingVariable(m_varBand);
12024 : }
12025 6 : else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
12026 : {
12027 : const auto oIndexingVarType =
12028 2 : GDALExtendedDataType::Create(GDT_Int32);
12029 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12030 4 : {poBandDim}, oIndexingVarType);
12031 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12032 3 : for (int i = 0; i < nBandCount; ++i)
12033 : {
12034 2 : const int anBandIdx[] = {i + 1};
12035 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12036 2 : const size_t anCount[] = {1};
12037 2 : const GInt64 arrayStep[] = {1};
12038 2 : const GPtrDiff_t anBufferStride[] = {1};
12039 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12040 : oIndexingVarType, anBandIdx);
12041 : }
12042 1 : m_varBand = std::move(poBandVar);
12043 1 : poBandDim->SetIndexingVariable(m_varBand);
12044 : }
12045 5 : else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
12046 : {
12047 1 : size_t nMaxLen = 0;
12048 3 : for (int i = 0; i < nBandCount; ++i)
12049 : {
12050 2 : const char *pszDesc = GDALGetColorInterpretationName(
12051 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12052 2 : nMaxLen = std::max(nMaxLen, strlen(pszDesc));
12053 : }
12054 : const auto oIndexingVarType =
12055 2 : GDALExtendedDataType::CreateString(nMaxLen);
12056 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12057 4 : {poBandDim}, oIndexingVarType);
12058 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12059 3 : for (int i = 0; i < nBandCount; ++i)
12060 : {
12061 2 : const char *pszDesc = GDALGetColorInterpretationName(
12062 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12063 2 : const char *const apszBandVal[] = {pszDesc};
12064 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12065 2 : const size_t anCount[] = {1};
12066 2 : const GInt64 arrayStep[] = {1};
12067 2 : const GPtrDiff_t anBufferStride[] = {1};
12068 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12069 : oIndexingVarType, apszBandVal);
12070 : }
12071 1 : m_varBand = std::move(poBandVar);
12072 1 : poBandDim->SetIndexingVariable(m_varBand);
12073 : }
12074 4 : else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
12075 : {
12076 3 : const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
12077 : papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
12078 3 : size_t nMaxLen = 0;
12079 3 : if (EQUAL(pszBandIndexingVarType, "String"))
12080 : {
12081 3 : for (int i = 0; i < nBandCount; ++i)
12082 : {
12083 : const char *pszVal =
12084 2 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
12085 2 : pszBandIndexingVarItem);
12086 2 : if (pszVal)
12087 1 : nMaxLen = std::max(nMaxLen, strlen(pszVal));
12088 : }
12089 : }
12090 : const auto oIndexingVarType =
12091 3 : EQUAL(pszBandIndexingVarType, "String")
12092 : ? GDALExtendedDataType::CreateString(nMaxLen)
12093 2 : : EQUAL(pszBandIndexingVarType, "Integer")
12094 : ? GDALExtendedDataType::Create(GDT_Int32)
12095 6 : : GDALExtendedDataType::Create(GDT_Float64);
12096 3 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12097 12 : {poBandDim}, oIndexingVarType);
12098 3 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12099 9 : for (int i = 0; i < nBandCount; ++i)
12100 : {
12101 6 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12102 6 : const size_t anCount[] = {1};
12103 6 : const GInt64 arrayStep[] = {1};
12104 6 : const GPtrDiff_t anBufferStride[] = {1};
12105 : const char *pszVal =
12106 6 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
12107 6 : pszBandIndexingVarItem);
12108 6 : if (oIndexingVarType.GetClass() == GEDTC_STRING)
12109 : {
12110 2 : const char *const apszBandVal[] = {pszVal ? pszVal : ""};
12111 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12112 : anBufferStride, oIndexingVarType,
12113 : apszBandVal);
12114 : }
12115 4 : else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12116 : {
12117 2 : const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12118 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12119 : anBufferStride, oIndexingVarType, anVal);
12120 : }
12121 : else
12122 : {
12123 2 : const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12124 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12125 : anBufferStride, oIndexingVarType, adfVal);
12126 : }
12127 : }
12128 3 : m_varBand = std::move(poBandVar);
12129 3 : poBandDim->SetIndexingVariable(m_varBand);
12130 : }
12131 :
12132 17 : GDALGeoTransform gt;
12133 17 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12134 : {
12135 24 : m_varX = GDALMDArrayRegularlySpaced::Create(
12136 16 : "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12137 8 : poXDim->SetIndexingVariable(m_varX);
12138 :
12139 24 : m_varY = GDALMDArrayRegularlySpaced::Create(
12140 16 : "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12141 8 : poYDim->SetIndexingVariable(m_varY);
12142 : }
12143 17 : if (bBandYX)
12144 : {
12145 96 : m_dims = {std::move(poBandDim), std::move(poYDim),
12146 80 : std::move(poXDim)};
12147 : }
12148 : else
12149 : {
12150 1 : m_iYDim = 0;
12151 1 : m_iXDim = 1;
12152 1 : m_iBandDim = 2;
12153 6 : m_dims = {std::move(poYDim), std::move(poXDim),
12154 5 : std::move(poBandDim)};
12155 : }
12156 17 : }
12157 :
12158 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12159 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12160 : const GDALExtendedDataType &bufferDataType,
12161 : void *pDstBuffer) const override;
12162 :
12163 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12164 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12165 : const GDALExtendedDataType &bufferDataType,
12166 : const void *pSrcBuffer) override
12167 : {
12168 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12169 : bufferStride, bufferDataType,
12170 1 : const_cast<void *>(pSrcBuffer));
12171 : }
12172 :
12173 : public:
12174 34 : ~GDALMDArrayFromDataset() override
12175 17 : {
12176 17 : m_poDS->ReleaseRef();
12177 34 : }
12178 :
12179 17 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12180 : CSLConstList papszOptions)
12181 : {
12182 : auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12183 34 : new GDALMDArrayFromDataset(poDS, papszOptions)));
12184 17 : array->SetSelf(array);
12185 34 : return array;
12186 : }
12187 :
12188 2 : bool IsWritable() const override
12189 : {
12190 2 : return m_poDS->GetAccess() == GA_Update;
12191 : }
12192 :
12193 14 : const std::string &GetFilename() const override
12194 : {
12195 14 : return m_osFilename;
12196 : }
12197 :
12198 : const std::vector<std::shared_ptr<GDALDimension>> &
12199 100 : GetDimensions() const override
12200 : {
12201 100 : return m_dims;
12202 : }
12203 :
12204 36 : const GDALExtendedDataType &GetDataType() const override
12205 : {
12206 36 : return m_dt;
12207 : }
12208 :
12209 5 : const std::string &GetUnit() const override
12210 : {
12211 5 : return m_osUnit;
12212 : }
12213 :
12214 5 : const void *GetRawNoDataValue() const override
12215 : {
12216 5 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12217 : }
12218 :
12219 5 : double GetOffset(bool *pbHasOffset,
12220 : GDALDataType *peStorageType) const override
12221 : {
12222 5 : double dfRes = 0;
12223 5 : int bHasOffset = false;
12224 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12225 5 : if (poFirstBand) // to avoid -Wnull-dereference
12226 : {
12227 5 : dfRes = poFirstBand->GetOffset(&bHasOffset);
12228 7 : for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12229 : {
12230 : const double dfOtherRes =
12231 2 : m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12232 2 : bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12233 : }
12234 : }
12235 5 : if (pbHasOffset)
12236 5 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12237 5 : if (peStorageType)
12238 3 : *peStorageType = GDT_Unknown;
12239 5 : return dfRes;
12240 : }
12241 :
12242 5 : double GetScale(bool *pbHasScale,
12243 : GDALDataType *peStorageType) const override
12244 : {
12245 5 : double dfRes = 0;
12246 5 : int bHasScale = false;
12247 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12248 5 : if (poFirstBand) // to avoid -Wnull-dereference
12249 : {
12250 5 : dfRes = poFirstBand->GetScale(&bHasScale);
12251 7 : for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12252 : {
12253 : const double dfOtherRes =
12254 2 : m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12255 2 : bHasScale = bHasScale && (dfOtherRes == dfRes);
12256 : }
12257 : }
12258 5 : if (pbHasScale)
12259 5 : *pbHasScale = CPL_TO_BOOL(bHasScale);
12260 5 : if (peStorageType)
12261 3 : *peStorageType = GDT_Unknown;
12262 5 : return dfRes;
12263 : }
12264 :
12265 9 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12266 : {
12267 9 : auto poSrcSRS = m_poDS->GetSpatialRef();
12268 9 : if (!poSrcSRS)
12269 1 : return nullptr;
12270 16 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12271 :
12272 16 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12273 24 : for (auto &m : axisMapping)
12274 : {
12275 16 : if (m == 1)
12276 8 : m = m_iXDim + 1;
12277 8 : else if (m == 2)
12278 8 : m = m_iYDim + 1;
12279 : else
12280 0 : m = 0;
12281 : }
12282 8 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12283 8 : return poSRS;
12284 : }
12285 :
12286 7 : std::vector<GUInt64> GetBlockSize() const override
12287 : {
12288 7 : int nBlockXSize = 0;
12289 7 : int nBlockYSize = 0;
12290 7 : m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12291 7 : if (m_iBandDim == 0)
12292 : {
12293 6 : return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12294 6 : static_cast<GUInt64>(nBlockXSize)};
12295 : }
12296 : else
12297 : {
12298 1 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12299 1 : static_cast<GUInt64>(nBlockXSize), 1};
12300 : }
12301 : }
12302 :
12303 : std::vector<std::shared_ptr<GDALAttribute>>
12304 7 : GetAttributes(CSLConstList) const override
12305 : {
12306 7 : std::vector<std::shared_ptr<GDALAttribute>> res;
12307 7 : auto papszMD = m_poDS->GetMetadata();
12308 14 : for (auto iter = papszMD; iter && iter[0]; ++iter)
12309 : {
12310 7 : char *pszKey = nullptr;
12311 7 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12312 7 : if (pszKey && pszValue)
12313 : {
12314 : res.emplace_back(
12315 7 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12316 : }
12317 7 : CPLFree(pszKey);
12318 : }
12319 7 : return res;
12320 : }
12321 :
12322 6 : int GetOverviewCount() const override
12323 : {
12324 6 : int nOvrCount = 0;
12325 6 : GDALDataset *poOvrDS = nullptr;
12326 6 : bool bOK = true;
12327 12 : for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12328 : {
12329 6 : auto poBand = m_poDS->GetRasterBand(i);
12330 6 : const int nThisOvrCount = poBand->GetOverviewCount();
12331 6 : bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12332 6 : if (bOK)
12333 : {
12334 6 : nOvrCount = nThisOvrCount;
12335 6 : auto poFirstOvrBand = poBand->GetOverview(0);
12336 6 : bOK = poFirstOvrBand != nullptr;
12337 6 : if (bOK)
12338 : {
12339 6 : auto poThisOvrDS = poFirstOvrBand->GetDataset();
12340 12 : bOK = poThisOvrDS != nullptr &&
12341 6 : poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12342 0 : (i == 1 || poThisOvrDS == poOvrDS);
12343 6 : if (bOK)
12344 6 : poOvrDS = poThisOvrDS;
12345 : }
12346 : }
12347 : }
12348 6 : return bOK ? nOvrCount : 0;
12349 : }
12350 :
12351 5 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12352 : {
12353 5 : const int nOverviews = GetOverviewCount();
12354 5 : if (idx < 0 || idx >= nOverviews)
12355 2 : return nullptr;
12356 3 : m_apoOverviews.resize(nOverviews);
12357 3 : if (!m_apoOverviews[idx])
12358 : {
12359 1 : if (auto poBand = m_poDS->GetRasterBand(1))
12360 : {
12361 1 : if (auto poOvrBand = poBand->GetOverview(idx))
12362 : {
12363 1 : if (auto poOvrDS = poOvrBand->GetDataset())
12364 : {
12365 1 : m_apoOverviews[idx] =
12366 2 : Create(poOvrDS, m_aosOptions.List());
12367 : }
12368 : }
12369 : }
12370 : }
12371 3 : return m_apoOverviews[idx];
12372 : }
12373 : };
12374 :
12375 8 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12376 : const size_t *count, const GInt64 *arrayStep,
12377 : const GPtrDiff_t *bufferStride,
12378 : const GDALExtendedDataType &bufferDataType,
12379 : void *pDstBuffer) const
12380 : {
12381 8 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12382 8 : bufferDataType, pDstBuffer);
12383 : }
12384 :
12385 : /************************************************************************/
12386 : /* ReadWrite() */
12387 : /************************************************************************/
12388 :
12389 9 : bool GDALMDArrayFromDataset::ReadWrite(
12390 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12391 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12392 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12393 : {
12394 9 : const auto eDT(bufferDataType.GetNumericDataType());
12395 9 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12396 9 : const int nX =
12397 9 : arrayStep[m_iXDim] > 0
12398 9 : ? static_cast<int>(arrayStartIdx[m_iXDim])
12399 0 : : static_cast<int>(arrayStartIdx[m_iXDim] -
12400 0 : (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12401 9 : const int nY =
12402 9 : arrayStep[m_iYDim] > 0
12403 9 : ? static_cast<int>(arrayStartIdx[m_iYDim])
12404 1 : : static_cast<int>(arrayStartIdx[m_iYDim] -
12405 1 : (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12406 : const int nSizeX =
12407 9 : static_cast<int>(count[m_iXDim] * std::abs(arrayStep[m_iXDim]));
12408 : const int nSizeY =
12409 9 : static_cast<int>(count[m_iYDim] * std::abs(arrayStep[m_iYDim]));
12410 9 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12411 9 : int nStrideXSign = 1;
12412 9 : if (arrayStep[m_iXDim] < 0)
12413 : {
12414 0 : pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12415 0 : nStrideXSign = -1;
12416 : }
12417 9 : int nStrideYSign = 1;
12418 9 : if (arrayStep[m_iYDim] < 0)
12419 : {
12420 1 : pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12421 1 : nStrideYSign = -1;
12422 : }
12423 9 : const GSpacing nPixelSpace =
12424 9 : static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12425 9 : const GSpacing nLineSpace =
12426 9 : static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12427 9 : const GSpacing nBandSpace =
12428 9 : static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12429 9 : std::vector<int> anBandList;
12430 26 : for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12431 17 : anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12432 17 : i * static_cast<int>(arrayStep[m_iBandDim]));
12433 :
12434 27 : return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12435 9 : static_cast<int>(count[m_iXDim]),
12436 9 : static_cast<int>(count[m_iYDim]), eDT,
12437 9 : static_cast<int>(count[m_iBandDim]),
12438 9 : anBandList.data(), nPixelSpace, nLineSpace,
12439 18 : nBandSpace, nullptr) == CE_None;
12440 : }
12441 :
12442 : /************************************************************************/
12443 : /* AsMDArray() */
12444 : /************************************************************************/
12445 :
12446 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12447 : *
12448 : * If this dataset is not already marked as shared, it will be, so that the
12449 : * returned array holds a reference to it.
12450 : *
12451 : * If the dataset has a geotransform attached, the X and Y dimensions of the
12452 : * returned array will have an associated indexing variable.
12453 : *
12454 : * The currently supported list of options is:
12455 : * <ul>
12456 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12457 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
12458 : * and the last (fastest changing direction) is X
12459 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
12460 : * and the last (fastest changing direction) is Band.
12461 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12462 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12463 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12464 : * "Y,X,Band" is use.
12465 : * </li>
12466 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
12467 : * item from which to build the band indexing variable.
12468 : * <ul>
12469 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12470 : * <li>"{None}" means that no band indexing variable must be created.</li>
12471 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
12472 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12473 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
12474 : * </ul>
12475 : * </li>
12476 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12477 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12478 : * Defaults to String.
12479 : * </li>
12480 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
12481 : * Defaults to "Band".
12482 : * </li>
12483 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
12484 : * </li>
12485 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
12486 : * </li>
12487 : * </ul>
12488 : *
12489 : * This is the same as the C function GDALDatasetAsMDArray().
12490 : *
12491 : * The "reverse" method is GDALMDArray::AsClassicDataset().
12492 : *
12493 : * @param papszOptions Null-terminated list of strings, or nullptr.
12494 : * @return a new array, or nullptr.
12495 : *
12496 : * @since GDAL 3.12
12497 : */
12498 19 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12499 : {
12500 19 : if (!GetShared())
12501 : {
12502 18 : MarkAsShared();
12503 : }
12504 19 : if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12505 : {
12506 1 : ReportError(
12507 : CE_Failure, CPLE_AppDefined,
12508 : "Degenerated array (band, Y and/or X dimension of size zero)");
12509 1 : return nullptr;
12510 : }
12511 18 : const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12512 31 : for (int i = 1; i < nBands; ++i)
12513 : {
12514 14 : if (eDT != papoBands[i]->GetRasterDataType())
12515 : {
12516 1 : ReportError(CE_Failure, CPLE_AppDefined,
12517 : "Non-uniform data type amongst bands");
12518 1 : return nullptr;
12519 : }
12520 : }
12521 : const char *pszDimOrder =
12522 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12523 17 : if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12524 2 : !EQUAL(pszDimOrder, "Y,X,Band"))
12525 : {
12526 1 : ReportError(CE_Failure, CPLE_IllegalArg,
12527 : "Illegal value for DIM_ORDER option");
12528 1 : return nullptr;
12529 : }
12530 16 : return GDALMDArrayFromDataset::Create(this, papszOptions);
12531 : }
12532 :
12533 : /************************************************************************/
12534 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12535 : /************************************************************************/
12536 :
12537 : /**
12538 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12539 :
12540 : The covariance indicates the level to which two bands vary together.
12541 :
12542 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12543 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12544 :
12545 : \f[
12546 : \mathrm{cov}[i,j] =
12547 : \frac{
12548 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12549 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12550 : }{
12551 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12552 : }
12553 : \f]
12554 :
12555 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12556 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12557 : is symmetric.
12558 :
12559 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12560 : if the pixels in bands are considered to be a sample of the whole population.
12561 : This is consistent with the default of
12562 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12563 : matrix is consistent with what can be obtained with
12564 :
12565 : \verbatim embed:rst
12566 : .. code-block:: python
12567 :
12568 : numpy.cov(
12569 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12570 : )
12571 : \endverbatim
12572 :
12573 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12574 : to be the whole population.
12575 :
12576 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12577 : this method uses them.
12578 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12579 : Otherwise, if bForce is false, an empty vector is returned
12580 :
12581 : @param nBandCount Zero for all bands, or number of values in panBandList.
12582 : Defaults to 0.
12583 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12584 : nBandCount values such as panBandList[i] is the index
12585 : between 1 and GetRasterCount() of a band that must be used
12586 : in the covariance computation. Defaults to nullptr.
12587 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12588 : ComputeInterBandCovarianceMatrix().
12589 : Defaults to false.
12590 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12591 : when the STATISTICS_COVARIANCES metadata items are missing.
12592 : Defaults to false.
12593 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12594 : write STATISTICS_COVARIANCES band metadata items.
12595 : Defaults to true.
12596 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12597 : averaging phase of the covariance computation.
12598 : Defaults to 1.
12599 : @param pfnProgress a function to call to report progress, or NULL.
12600 : @param pProgressData application data to pass to the progress function.
12601 :
12602 : @return a vector of nBandCount * nBandCount values if successful,
12603 : in row-major order, or an empty vector in case of failure
12604 :
12605 : @since 3.13
12606 :
12607 : @see ComputeInterBandCovarianceMatrix()
12608 : */
12609 :
12610 0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12611 : int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12612 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12613 : GDALProgressFunc pfnProgress, void *pProgressData)
12614 : {
12615 0 : std::vector<double> res;
12616 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12617 0 : if (nBandCountToUse == 0)
12618 0 : return res;
12619 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12620 : {
12621 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12622 : if (static_cast<uint32_t>(nBandCountToUse) >
12623 : std::numeric_limits<uint16_t>::max())
12624 : {
12625 : CPLError(CE_Failure, CPLE_OutOfMemory,
12626 : "Not enough memory to store result");
12627 : return res;
12628 : }
12629 : }
12630 : try
12631 : {
12632 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12633 : }
12634 0 : catch (const std::exception &)
12635 : {
12636 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12637 : "Not enough memory to store result");
12638 0 : return res;
12639 : }
12640 :
12641 0 : if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12642 : panBandList, bApproxOK, bForce,
12643 : bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12644 0 : pfnProgress, pProgressData) != CE_None)
12645 : {
12646 0 : res.clear();
12647 : }
12648 0 : return res;
12649 : }
12650 :
12651 : /************************************************************************/
12652 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12653 : /************************************************************************/
12654 :
12655 : /**
12656 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12657 :
12658 : The covariance indicates the level to which two bands vary together.
12659 :
12660 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12661 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12662 :
12663 : \f[
12664 : \mathrm{cov}[i,j] =
12665 : \frac{
12666 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12667 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12668 : }{
12669 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12670 : }
12671 : \f]
12672 :
12673 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12674 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12675 : is symmetric.
12676 :
12677 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12678 : if the pixels in bands are considered to be a sample of the whole population.
12679 : This is consistent with the default of
12680 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12681 : matrix is consistent with what can be obtained with
12682 :
12683 : \verbatim embed:rst
12684 : .. code-block:: python
12685 :
12686 : numpy.cov(
12687 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12688 : )
12689 : \endverbatim
12690 :
12691 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12692 : to be the whole population.
12693 :
12694 : The caller must provide an already allocated array in padfCovMatrix of size
12695 : at least nBandCount * nBandCount.
12696 :
12697 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12698 : this method uses them.
12699 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12700 : Otherwise, if bForce is false, an empty vector is returned
12701 :
12702 : This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12703 :
12704 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12705 : nBandCount * nBandCount.
12706 : @param nSize Number of elements in output array.
12707 : @param nBandCount Zero for all bands, or number of values in panBandList.
12708 : Defaults to 0.
12709 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12710 : nBandCount values such as panBandList[i] is the index
12711 : between 1 and GetRasterCount() of a band that must be used
12712 : in the covariance computation. Defaults to nullptr.
12713 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12714 : ComputeInterBandCovarianceMatrix().
12715 : Defaults to false.
12716 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12717 : when the STATISTICS_COVARIANCES metadata items are missing.
12718 : Defaults to false.
12719 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12720 : write STATISTICS_COVARIANCES band metadata items.
12721 : Defaults to true.
12722 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12723 : averaging phase of the covariance computation.
12724 : Defaults to 1.
12725 : @param pfnProgress a function to call to report progress, or NULL.
12726 : @param pProgressData application data to pass to the progress function.
12727 :
12728 : @return CE_None if successful, CE_Warning if values are not available in
12729 : metadata and bForce is false, or CE_Failure in case of failure
12730 :
12731 : @since 3.13
12732 :
12733 : @see ComputeInterBandCovarianceMatrix()
12734 : */
12735 :
12736 11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12737 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12738 : bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12739 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12740 : void *pProgressData)
12741 : {
12742 22 : std::vector<int> anBandListTmp; // keep in this scope
12743 11 : if (nBandCount == 0)
12744 : {
12745 0 : if (nBands == 0)
12746 0 : return CE_None;
12747 0 : for (int i = 0; i < nBands; ++i)
12748 0 : anBandListTmp.push_back(i + 1);
12749 0 : nBandCount = nBands;
12750 0 : panBandList = anBandListTmp.data();
12751 : }
12752 : else
12753 : {
12754 11 : if (nBandCount > nBands)
12755 : {
12756 1 : CPLError(CE_Failure, CPLE_AppDefined,
12757 : "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12758 1 : return CE_Failure;
12759 : }
12760 29 : for (int i = 0; i < nBandCount; ++i)
12761 : {
12762 21 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
12763 : {
12764 2 : CPLError(CE_Failure, CPLE_AppDefined,
12765 : "GetInterBandCovarianceMatrix(): invalid value "
12766 : "panBandList[%d] = %d",
12767 2 : i, panBandList[i]);
12768 2 : return CE_Failure;
12769 : }
12770 : }
12771 : }
12772 :
12773 8 : if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12774 : {
12775 0 : CPLError(
12776 : CE_Failure, CPLE_AppDefined,
12777 : "GetInterBandCovarianceMatrix(): too small result matrix provided");
12778 0 : return CE_Failure;
12779 : }
12780 8 : bool bGotFromMD = true;
12781 8 : size_t resIdx = 0;
12782 20 : for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12783 : {
12784 24 : const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12785 12 : "STATISTICS_COVARIANCES");
12786 12 : bGotFromMD = pszCov != nullptr;
12787 12 : if (bGotFromMD)
12788 : {
12789 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12790 6 : bGotFromMD = aosTokens.size() == nBands;
12791 6 : if (bGotFromMD)
12792 : {
12793 24 : for (int j = 0; j < nBandCount; ++j)
12794 18 : padfCovMatrix[resIdx++] =
12795 18 : CPLAtof(aosTokens[panBandList[j] - 1]);
12796 : }
12797 : }
12798 : }
12799 8 : if (bGotFromMD)
12800 2 : return CE_None;
12801 :
12802 6 : if (!bForce)
12803 1 : return CE_Warning;
12804 5 : return ComputeInterBandCovarianceMatrix(
12805 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12806 5 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12807 : }
12808 :
12809 : /************************************************************************/
12810 : /* GDALDatasetGetInterBandCovarianceMatrix() */
12811 : /************************************************************************/
12812 :
12813 : /**
12814 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12815 :
12816 : The covariance indicates the level to which two bands vary together.
12817 :
12818 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12819 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12820 :
12821 : \f[
12822 : \mathrm{cov}[i,j] =
12823 : \frac{
12824 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12825 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12826 : }{
12827 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12828 : }
12829 : \f]
12830 :
12831 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12832 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12833 : is symmetric.
12834 :
12835 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12836 : if the pixels in bands are considered to be a sample of the whole population.
12837 : This is consistent with the default of
12838 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12839 : matrix is consistent with what can be obtained with
12840 :
12841 : \verbatim embed:rst
12842 : .. code-block:: python
12843 :
12844 : numpy.cov(
12845 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12846 : )
12847 : \endverbatim
12848 :
12849 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12850 : to be the whole population.
12851 :
12852 : The caller must provide an already allocated array in padfCovMatrix of size
12853 : at least nBandCount * nBandCount.
12854 :
12855 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12856 : this method uses them.
12857 : Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12858 : Otherwise, if bForce is false, an empty vector is returned
12859 :
12860 : This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12861 :
12862 : @param hDS Dataset handle.
12863 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12864 : nBandCount * nBandCount.
12865 : @param nSize Number of elements in output array.
12866 : @param nBandCount Zero for all bands, or number of values in panBandList.
12867 : Defaults to 0.
12868 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12869 : nBandCount values such as panBandList[i] is the index
12870 : between 1 and GetRasterCount() of a band that must be used
12871 : in the covariance computation. Defaults to nullptr.
12872 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12873 : GDALDatasetComputeInterBandCovarianceMatrix().
12874 : Defaults to false.
12875 : @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12876 : when the STATISTICS_COVARIANCES metadata items are missing.
12877 : Defaults to false.
12878 : @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12879 : write STATISTICS_COVARIANCES band metadata items.
12880 : Defaults to true.
12881 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12882 : averaging phase of the covariance computation.
12883 : Defaults to 1.
12884 : @param pfnProgress a function to call to report progress, or NULL.
12885 : @param pProgressData application data to pass to the progress function.
12886 :
12887 : @return CE_None if successful, CE_Warning if values are not available in
12888 : metadata and bForce is false, or CE_Failure in case of failure
12889 :
12890 : @since 3.13
12891 :
12892 : @see GDALDatasetComputeInterBandCovarianceMatrix()
12893 : */
12894 11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12895 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12896 : const int *panBandList, bool bApproxOK, bool bForce,
12897 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12898 : GDALProgressFunc pfnProgress, void *pProgressData)
12899 : {
12900 11 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12901 11 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12902 11 : return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12903 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12904 11 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12905 : }
12906 :
12907 : /************************************************************************/
12908 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
12909 : /************************************************************************/
12910 :
12911 : /**
12912 : \brief Compute the covariance matrix between bands of this dataset.
12913 :
12914 : The covariance indicates the level to which two bands vary together.
12915 :
12916 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12917 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12918 :
12919 : \f[
12920 : \mathrm{cov}[i,j] =
12921 : \frac{
12922 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12923 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12924 : }{
12925 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12926 : }
12927 : \f]
12928 :
12929 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12930 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12931 : is symmetric.
12932 :
12933 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12934 : if the pixels in bands are considered to be a sample of the whole population.
12935 : This is consistent with the default of
12936 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12937 : matrix is consistent with what can be obtained with
12938 :
12939 : \verbatim embed:rst
12940 : .. code-block:: python
12941 :
12942 : numpy.cov(
12943 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12944 : )
12945 : \endverbatim
12946 :
12947 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12948 : to be the whole population.
12949 :
12950 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12951 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
12952 : to use them.
12953 :
12954 : @param nBandCount Zero for all bands, or number of values in panBandList.
12955 : Defaults to 0.
12956 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12957 : nBandCount values such as panBandList[i] is the index
12958 : between 1 and GetRasterCount() of a band that must be used
12959 : in the covariance computation. Defaults to nullptr.
12960 : @param bApproxOK Whether it is acceptable to use a subsample of values.
12961 : Defaults to false.
12962 : @param bWriteIntoMetadata Whether this method must write
12963 : STATISTICS_COVARIANCES band metadata items.
12964 : Defaults to true.
12965 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12966 : averaging phase of the covariance computation.
12967 : Defaults to 1.
12968 : @param pfnProgress a function to call to report progress, or NULL.
12969 : @param pProgressData application data to pass to the progress function.
12970 :
12971 : @return a vector of nBandCount * nBandCount values if successful,
12972 : in row-major order, or an empty vector in case of failure
12973 :
12974 : @since 3.13
12975 :
12976 : @see GetInterBandCovarianceMatrix()
12977 : */
12978 0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12979 : int nBandCount, const int *panBandList, bool bApproxOK,
12980 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12981 : GDALProgressFunc pfnProgress, void *pProgressData)
12982 : {
12983 0 : std::vector<double> res;
12984 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12985 0 : if (nBandCountToUse == 0)
12986 0 : return res;
12987 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12988 : {
12989 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12990 : if (static_cast<uint32_t>(nBandCountToUse) >
12991 : std::numeric_limits<uint16_t>::max())
12992 : {
12993 : CPLError(CE_Failure, CPLE_OutOfMemory,
12994 : "Not enough memory to store result");
12995 : return res;
12996 : }
12997 : }
12998 : try
12999 : {
13000 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
13001 : }
13002 0 : catch (const std::exception &)
13003 : {
13004 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
13005 : "Not enough memory to store result");
13006 0 : return res;
13007 : }
13008 :
13009 0 : if (ComputeInterBandCovarianceMatrix(
13010 : res.data(), res.size(), nBandCount, panBandList, bApproxOK,
13011 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
13012 0 : pProgressData) != CE_None)
13013 0 : res.clear();
13014 0 : return res;
13015 : }
13016 :
13017 : /************************************************************************/
13018 : /* ComputeInterBandCovarianceMatrixInternal() */
13019 : /************************************************************************/
13020 :
13021 : template <class T>
13022 : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
13023 : // causes that to happen
13024 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
13025 15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
13026 : double *padfCovMatrix, int nBandCount,
13027 : const int *panBandList,
13028 : GDALRasterBand *const *papoBands,
13029 : int nDeltaDegreeOfFreedom,
13030 : GDALProgressFunc pfnProgress,
13031 : void *pProgressData)
13032 : {
13033 : // We use the padfCovMatrix to accumulate co-moments
13034 : // Dimension = nBandCount * nBandCount
13035 15 : double *const padfComomentMatrix = padfCovMatrix;
13036 :
13037 : // Matrix of nBandCount * nBandCount storing co-moments, in optimized
13038 : // case when the block has no nodata value
13039 : // Only used if T != double
13040 30 : [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
13041 :
13042 : // Count number of valid values in padfComomentMatrix for each (i,j) tuple
13043 : // Updated while iterating over blocks
13044 : // Dimension = nBandCount * nBandCount
13045 30 : std::vector<uint64_t> anCount;
13046 :
13047 : // Mean of bands, for each (i,j) tuple.
13048 : // Updated while iterating over blocks.
13049 : // This is a matrix rather than a vector due to the fact when need to update
13050 : // it in sync with padfComomentMatrix
13051 : // Dimension = nBandCount * nBandCount
13052 30 : std::vector<T> adfMean;
13053 :
13054 : // Number of valid values when computing adfMean, for each (i,j) tuple.
13055 : // Updated while iterating over blocks.
13056 : // This is a matrix rather than a vector due to the fact when need to update
13057 : // it in sync with padfComomentMatrix
13058 : // Dimension = nBandCount * nBandCount
13059 30 : std::vector<uint64_t> anCountMean;
13060 :
13061 : // Mean of values for each band i. Refreshed for each block.
13062 : // Dimension = nBandCount
13063 30 : std::vector<T> adfCurBlockMean;
13064 :
13065 : // Number of values participating to the mean for each band i.
13066 : // Refreshed for each block. Dimension = nBandCount
13067 30 : std::vector<size_t> anCurBlockCount;
13068 :
13069 : // Pixel values for all selected values for the current block
13070 : // Dimension = nBlockXSize * nBlockYSize * nBandCount
13071 30 : std::vector<T> adfCurBlockPixelsAllBands;
13072 :
13073 : // Vector of nodata values for all bands. Dimension = nBandCount
13074 30 : std::vector<T> adfNoData;
13075 :
13076 : // Vector of mask bands for all bands. Dimension = nBandCount
13077 30 : std::vector<GDALRasterBand *> apoMaskBands;
13078 :
13079 : // Vector of vector of mask values. Dimension = nBandCount
13080 30 : std::vector<std::vector<GByte>> aabyCurBlockMask;
13081 :
13082 : // Vector of pointer to vector of mask values. Dimension = nBandCount
13083 30 : std::vector<std::vector<GByte> *> pabyCurBlockMask;
13084 :
13085 15 : int nBlockXSize = 0;
13086 15 : int nBlockYSize = 0;
13087 15 : papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
13088 :
13089 30 : if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
13090 15 : std::numeric_limits<size_t>::max() / nBandCount)
13091 : {
13092 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13093 : "Not enough memory for intermediate computations");
13094 0 : return CE_Failure;
13095 : }
13096 15 : const size_t nPixelsInBlock =
13097 15 : static_cast<size_t>(nBlockXSize) * nBlockYSize;
13098 :
13099 : // Allocate temporary matrices and vectors
13100 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13101 :
13102 : using MySignedSize_t = std::make_signed_t<size_t>;
13103 15 : const auto kMax =
13104 15 : static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
13105 30 : std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
13106 : try
13107 : {
13108 15 : anCount.resize(nMatrixSize);
13109 15 : adfMean.resize(nMatrixSize);
13110 15 : anCountMean.resize(nMatrixSize);
13111 :
13112 : if constexpr (!std::is_same_v<T, double>)
13113 : {
13114 : aCurBlockComomentMatrix.resize(nMatrixSize);
13115 : }
13116 :
13117 15 : anMapLinearIdxToIJ.resize(kMax);
13118 :
13119 15 : adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13120 :
13121 15 : adfCurBlockMean.resize(nBandCount);
13122 15 : anCurBlockCount.resize(nBandCount);
13123 15 : adfNoData.resize(nBandCount);
13124 15 : apoMaskBands.resize(nBandCount);
13125 15 : aabyCurBlockMask.resize(nBandCount);
13126 15 : pabyCurBlockMask.resize(nBandCount);
13127 : }
13128 0 : catch (const std::exception &)
13129 : {
13130 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13131 : "Not enough memory for intermediate computations");
13132 0 : return CE_Failure;
13133 : }
13134 :
13135 15 : constexpr T ZERO{0};
13136 15 : std::fill(padfComomentMatrix,
13137 15 : padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13138 15 : 0);
13139 :
13140 : {
13141 15 : MySignedSize_t nLinearIdx = 0;
13142 1045 : for (int i = 0; i < nBandCount; ++i)
13143 : {
13144 501581 : for (int j = i; j < nBandCount; ++j)
13145 : {
13146 500551 : anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13147 500551 : ++nLinearIdx;
13148 : }
13149 : }
13150 : }
13151 :
13152 : // Fetch nodata values and mask bands
13153 15 : bool bAllBandsSameMask = false;
13154 15 : bool bIsAllInteger = false;
13155 15 : bool bNoneHasMaskOrNodata = false;
13156 1045 : for (int i = 0; i < nBandCount; ++i)
13157 : {
13158 1030 : const auto poBand = papoBands[panBandList[i] - 1];
13159 2057 : bIsAllInteger = (i == 0 || bIsAllInteger) &&
13160 1027 : GDALDataTypeIsInteger(poBand->GetRasterDataType());
13161 1030 : int bHasNoData = FALSE;
13162 1030 : double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13163 1030 : if (!bHasNoData)
13164 : {
13165 1028 : dfNoData = std::numeric_limits<double>::quiet_NaN();
13166 :
13167 1032 : if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13168 4 : poBand->GetColorInterpretation() != GCI_AlphaBand)
13169 : {
13170 4 : apoMaskBands[i] = poBand->GetMaskBand();
13171 : try
13172 : {
13173 4 : aabyCurBlockMask[i].resize(nPixelsInBlock);
13174 : }
13175 0 : catch (const std::exception &)
13176 : {
13177 0 : poDS->ReportError(
13178 : CE_Failure, CPLE_OutOfMemory,
13179 : "Not enough memory for intermediate computations");
13180 0 : return CE_Failure;
13181 : }
13182 : #ifndef __COVERITY__
13183 : // coverity[escape]
13184 4 : pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13185 : #endif
13186 : }
13187 : }
13188 1030 : adfNoData[i] = static_cast<T>(dfNoData);
13189 1030 : if (i == 0)
13190 15 : bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13191 1015 : else if (bAllBandsSameMask)
13192 2 : bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13193 :
13194 3072 : bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13195 3072 : std::isnan(dfNoData) &&
13196 1026 : apoMaskBands[i] == nullptr;
13197 : }
13198 15 : if (bAllBandsSameMask)
13199 : {
13200 2 : for (int i = 1; i < nBandCount; ++i)
13201 : {
13202 1 : apoMaskBands[i] = nullptr;
13203 1 : aabyCurBlockMask[i].clear();
13204 1 : pabyCurBlockMask[i] = pabyCurBlockMask[0];
13205 : }
13206 : }
13207 :
13208 15 : const auto nIterCount =
13209 : static_cast<uint64_t>(
13210 15 : cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13211 15 : cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13212 15 : uint64_t nCurIter = 0;
13213 :
13214 15 : int nNumThreads = 1;
13215 : #ifdef HAVE_OPENMP
13216 15 : if (nBandCount >= 100)
13217 : {
13218 1 : const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13219 : nNumThreads =
13220 1 : GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13221 : }
13222 : #endif
13223 :
13224 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13225 30 : const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13226 30 : __builtin_cpu_supports("avx2") &&
13227 : __builtin_cpu_supports("fma");
13228 : #endif
13229 :
13230 : // Iterate over all blocks
13231 77 : for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13232 : {
13233 32 : const auto nThisBlockPixelCount =
13234 32 : static_cast<size_t>(window.nXSize) * window.nYSize;
13235 :
13236 : // Extract pixel values and masks
13237 96 : CPLErr eErr = poDS->RasterIO(
13238 32 : GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13239 32 : adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13240 : gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13241 : nullptr);
13242 32 : if (eErr == CE_None && bAllBandsSameMask)
13243 : {
13244 2 : eErr = apoMaskBands[0]->RasterIO(
13245 1 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13246 1 : window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13247 1 : window.nYSize, GDT_Byte, 0, 0, nullptr);
13248 : }
13249 : else
13250 : {
13251 1108 : for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13252 : {
13253 1077 : if (apoMaskBands[i])
13254 : {
13255 4 : eErr = apoMaskBands[i]->RasterIO(
13256 2 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13257 2 : window.nYSize, aabyCurBlockMask[i].data(),
13258 2 : window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13259 : }
13260 : }
13261 : }
13262 32 : if (eErr != CE_None)
13263 1 : return eErr;
13264 :
13265 : // Compute the mean of all bands for this block
13266 32 : bool bAllBandsAreAllNodata = false;
13267 32 : bool bNoBandHasNodata = false;
13268 1111 : for (int i = 0; i < nBandCount; ++i)
13269 : {
13270 1079 : T dfSum = 0;
13271 1079 : size_t nCount = 0;
13272 1079 : const T dfNoDataI = adfNoData[i];
13273 1079 : const T *padfI =
13274 1079 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13275 : #ifdef HAVE_OPENMP_SIMD
13276 1079 : #pragma omp simd reduction(+ : dfSum)
13277 : #endif
13278 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13279 : {
13280 822482 : const T dfI = padfI[iPixel];
13281 822482 : const bool bIsValid =
13282 1644950 : !std::isnan(dfI) && dfI != dfNoDataI &&
13283 822466 : (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13284 822482 : nCount += bIsValid;
13285 822482 : dfSum += bIsValid ? dfI : ZERO;
13286 : }
13287 1079 : adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13288 1079 : anCurBlockCount[i] = nCount;
13289 1079 : bAllBandsAreAllNodata =
13290 1079 : (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13291 1079 : bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13292 : (nCount == nThisBlockPixelCount);
13293 : }
13294 :
13295 : // Modify the pixel values to shift them by minus the mean
13296 32 : if (!bAllBandsAreAllNodata)
13297 : {
13298 1103 : for (int i = 0; i < nBandCount; ++i)
13299 : {
13300 1074 : T *padfI =
13301 1074 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13302 1074 : const T dfMeanI = adfCurBlockMean[i];
13303 823546 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13304 : {
13305 822472 : padfI[iPixel] -= dfMeanI;
13306 : }
13307 : }
13308 : }
13309 :
13310 : // Update padfComomentMatrix, anCount, adfMean, anCountMean
13311 : // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13312 32 : const auto UpdateGlobalValues =
13313 13507600 : [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13314 : &anCurBlockCount, padfComomentMatrix,
13315 : nBandCount](int i, int j, size_t nCount, T dfComoment)
13316 : {
13317 500647 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13318 500647 : const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13319 :
13320 : // Update the total comoment using last formula of paragraph
13321 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13322 : // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13323 : // (mean_I(A) - mean_I(B)) *
13324 : // (mean_J(A) - mean_J(B)) *
13325 : // (count(A) * count(B)) / (count(A) + count(B))
13326 : //
13327 : // There might be a small gotcha in the fact that the set of
13328 : // pixels on which the means are computed is not always the
13329 : // same as the the one on which the comoment is computed, if
13330 : // pixels are not valid/invalid at the same indices among bands
13331 : // It is not obvious (to me) what should be the correct behavior.
13332 : // The current approach has the benefit to avoid recomputing
13333 : // the mean for each (i,j) tuple, but only for all i.
13334 500647 : if (nCount > 0)
13335 : {
13336 500639 : padfComomentMatrix[idxInMatrixI] +=
13337 : static_cast<double>(dfComoment);
13338 500639 : padfComomentMatrix[idxInMatrixI] +=
13339 500639 : static_cast<double>(adfMean[idxInMatrixI] -
13340 500639 : adfCurBlockMean[i]) *
13341 500639 : static_cast<double>(adfMean[idxInMatrixJ] -
13342 500639 : adfCurBlockMean[j]) *
13343 500639 : (static_cast<double>(anCount[idxInMatrixI]) *
13344 500639 : static_cast<double>(nCount) /
13345 500639 : static_cast<double>(anCount[idxInMatrixI] + nCount));
13346 :
13347 500639 : anCount[idxInMatrixI] += nCount;
13348 : }
13349 :
13350 : // Update means
13351 500647 : if (anCurBlockCount[i] > 0)
13352 : {
13353 1001280 : adfMean[idxInMatrixI] +=
13354 500640 : (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13355 : static_cast<T>(
13356 500640 : static_cast<double>(anCurBlockCount[i]) /
13357 500640 : static_cast<double>(anCountMean[idxInMatrixI] +
13358 : anCurBlockCount[i]));
13359 :
13360 500640 : anCountMean[idxInMatrixI] += anCurBlockCount[i];
13361 : }
13362 :
13363 500647 : if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13364 : {
13365 999132 : adfMean[idxInMatrixJ] +=
13366 499566 : (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13367 : static_cast<T>(
13368 499566 : static_cast<double>(anCurBlockCount[j]) /
13369 499566 : static_cast<double>(anCountMean[idxInMatrixJ] +
13370 : anCurBlockCount[j]));
13371 :
13372 499566 : anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13373 : }
13374 : };
13375 :
13376 32 : if (bAllBandsAreAllNodata)
13377 : {
13378 : // Optimized code path where all values in the current block
13379 : // are invalid
13380 :
13381 8 : for (int i = 0; i < nBandCount; ++i)
13382 : {
13383 12 : for (int j = i; j < nBandCount; ++j)
13384 : {
13385 7 : UpdateGlobalValues(i, j, 0, ZERO);
13386 : }
13387 : }
13388 : }
13389 29 : else if (bNoBandHasNodata)
13390 : {
13391 : // Optimized code path where there are no invalid value in the
13392 : // current block
13393 :
13394 : if constexpr (!std::is_same_v<T, double>)
13395 : {
13396 : std::fill(aCurBlockComomentMatrix.begin(),
13397 : aCurBlockComomentMatrix.end(), ZERO);
13398 :
13399 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13400 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13401 : aCurBlockComomentMatrix.data(), nBandCount,
13402 : nThisBlockPixelCount);
13403 : }
13404 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13405 24 : else if (bHasAVX2_FMA)
13406 : {
13407 24 : GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13408 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13409 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13410 : }
13411 : #endif
13412 : else
13413 : {
13414 0 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13415 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13416 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13417 : }
13418 :
13419 1088 : for (int i = 0; i < nBandCount; ++i)
13420 : {
13421 501689 : for (int j = i; j < nBandCount; ++j)
13422 : {
13423 : if constexpr (!std::is_same_v<T, double>)
13424 : {
13425 : const auto idxInMatrixI =
13426 : static_cast<size_t>(i) * nBandCount + j;
13427 : UpdateGlobalValues(
13428 : i, j, nThisBlockPixelCount,
13429 : aCurBlockComomentMatrix[idxInMatrixI]);
13430 : }
13431 : else
13432 : {
13433 500625 : UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13434 : }
13435 : }
13436 : }
13437 : }
13438 : else
13439 : {
13440 : #ifdef HAVE_OPENMP
13441 5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
13442 : #endif
13443 : for (MySignedSize_t k = 0; k < kMax; ++k)
13444 : {
13445 : int i, j;
13446 : std::tie(i, j) = anMapLinearIdxToIJ[k];
13447 :
13448 : // Now compute the moment of (i, j), but just for this block
13449 : size_t nCount = 0;
13450 : T dfComoment = 0;
13451 : const T *padfI =
13452 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13453 : const T *padfJ =
13454 : adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13455 :
13456 : // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13457 : // for the current block
13458 : if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13459 : anCurBlockCount[j] == nThisBlockPixelCount) ||
13460 : (bNoneHasMaskOrNodata && bIsAllInteger))
13461 : {
13462 : // Most optimized code path: integer, no nodata, no mask
13463 : #ifdef HAVE_OPENMP_SIMD
13464 : #pragma omp simd reduction(+ : dfComoment)
13465 : #endif
13466 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13467 : ++iPixel)
13468 : {
13469 : dfComoment += padfI[iPixel] * padfJ[iPixel];
13470 : }
13471 : nCount = nThisBlockPixelCount;
13472 : }
13473 : else if (bNoneHasMaskOrNodata)
13474 : {
13475 : // Floating-point code path with no nodata and no mask
13476 : #ifdef HAVE_OPENMP_SIMD
13477 : #pragma omp simd reduction(+ : dfComoment)
13478 : #endif
13479 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13480 : ++iPixel)
13481 : {
13482 : const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13483 : const bool bIsValid = !std::isnan(dfAcc);
13484 : nCount += bIsValid;
13485 : dfComoment += bIsValid ? dfAcc : ZERO;
13486 : }
13487 : }
13488 : else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13489 : {
13490 : // Code path when there are both nodata values
13491 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13492 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13493 :
13494 : #ifdef HAVE_OPENMP_SIMD
13495 : #pragma omp simd reduction(+ : dfComoment)
13496 : #endif
13497 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13498 : ++iPixel)
13499 : {
13500 : const T dfI = padfI[iPixel];
13501 : const T dfJ = padfJ[iPixel];
13502 : const T dfAcc = dfI * dfJ;
13503 : const bool bIsValid = !std::isnan(dfAcc) &&
13504 : dfI != shiftedNoDataI &&
13505 : dfJ != shiftedNoDataJ;
13506 : nCount += bIsValid;
13507 : dfComoment += bIsValid ? dfAcc : ZERO;
13508 : }
13509 : }
13510 : else
13511 : {
13512 : // Generic code path
13513 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13514 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13515 :
13516 : #ifdef HAVE_OPENMP_SIMD
13517 : #pragma omp simd reduction(+ : dfComoment)
13518 : #endif
13519 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13520 : ++iPixel)
13521 : {
13522 : const T dfI = padfI[iPixel];
13523 : const T dfJ = padfJ[iPixel];
13524 : const T dfAcc = dfI * dfJ;
13525 : const bool bIsValid =
13526 : !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13527 : dfJ != shiftedNoDataJ &&
13528 : (!pabyCurBlockMask[i] ||
13529 : (*pabyCurBlockMask[i])[iPixel]) &&
13530 : (!pabyCurBlockMask[j] ||
13531 : (*pabyCurBlockMask[j])[iPixel]);
13532 : nCount += bIsValid;
13533 : dfComoment += bIsValid ? dfAcc : ZERO;
13534 : }
13535 : }
13536 :
13537 : UpdateGlobalValues(i, j, nCount, dfComoment);
13538 : }
13539 : }
13540 :
13541 32 : ++nCurIter;
13542 35 : if (pfnProgress &&
13543 3 : !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13544 : pProgressData))
13545 : {
13546 1 : poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13547 : "User terminated");
13548 1 : return CE_Failure;
13549 : }
13550 : }
13551 :
13552 : // Finalize by dividing co-moments by the number of contributing values
13553 : // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13554 44 : for (int i = 0; i < nBandCount; ++i)
13555 : {
13556 : // The covariance matrix is symmetric. So start at i
13557 81 : for (int j = i; j < nBandCount; ++j)
13558 : {
13559 51 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13560 51 : const double dfCovariance =
13561 51 : (nDeltaDegreeOfFreedom < 0 ||
13562 51 : anCount[idxInMatrixI] <=
13563 51 : static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13564 4 : ? std::numeric_limits<double>::quiet_NaN()
13565 94 : : padfComomentMatrix[idxInMatrixI] /
13566 47 : static_cast<double>(anCount[idxInMatrixI] -
13567 47 : nDeltaDegreeOfFreedom);
13568 :
13569 51 : padfCovMatrix[idxInMatrixI] = dfCovariance;
13570 : // Fill lower triangle
13571 51 : padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13572 : dfCovariance;
13573 : }
13574 : }
13575 :
13576 14 : return CE_None;
13577 : }
13578 :
13579 : /************************************************************************/
13580 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
13581 : /************************************************************************/
13582 :
13583 : /**
13584 : \brief Compute the covariance matrix between bands of this dataset.
13585 :
13586 : The covariance indicates the level to which two bands vary together.
13587 :
13588 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13589 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13590 :
13591 : \f[
13592 : \mathrm{cov}[i,j] =
13593 : \frac{
13594 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13595 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13596 : }{
13597 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13598 : }
13599 : \f]
13600 :
13601 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13602 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13603 : is symmetric.
13604 :
13605 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13606 : if the pixels in bands are considered to be a sample of the whole population.
13607 : This is consistent with the default of
13608 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13609 : matrix is consistent with what can be obtained with
13610 :
13611 : \verbatim embed:rst
13612 : .. code-block:: python
13613 :
13614 : numpy.cov(
13615 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13616 : )
13617 : \endverbatim
13618 :
13619 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13620 : to be the whole population.
13621 :
13622 : The caller must provide an already allocated array in padfCovMatrix of size
13623 : at least nBandCount * nBandCount.
13624 :
13625 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13626 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
13627 : to use them.
13628 :
13629 : The implementation is optimized to minimize the amount of pixel reading.
13630 :
13631 : This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13632 :
13633 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13634 : nBandCount * nBandCount.
13635 : @param nSize Number of elements in output array.
13636 : @param nBandCount Zero for all bands, or number of values in panBandList.
13637 : Defaults to 0.
13638 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13639 : nBandCount values such as panBandList[i] is the index
13640 : between 1 and GetRasterCount() of a band that must be used
13641 : in the covariance computation. Defaults to nullptr.
13642 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13643 : Defaults to false.
13644 : @param bWriteIntoMetadata Whether this method must write
13645 : STATISTICS_COVARIANCES band metadata items.
13646 : Defaults to true.
13647 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13648 : averaging phase of the covariance computation.
13649 : Defaults to 1.
13650 : @param pfnProgress a function to call to report progress, or NULL.
13651 : @param pProgressData application data to pass to the progress function.
13652 :
13653 : @return CE_None if successful, or CE_Failure in case of failure
13654 :
13655 : @since 3.13
13656 :
13657 : @see GetInterBandCovarianceMatrix()
13658 : */
13659 22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13660 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13661 : bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13662 : GDALProgressFunc pfnProgress, void *pProgressData)
13663 : {
13664 44 : std::vector<int> anBandListTmp; // keep in this scope
13665 22 : if (nBandCount == 0)
13666 : {
13667 0 : if (nBands == 0)
13668 0 : return CE_None;
13669 0 : for (int i = 0; i < nBands; ++i)
13670 0 : anBandListTmp.push_back(i + 1);
13671 0 : nBandCount = nBands;
13672 0 : panBandList = anBandListTmp.data();
13673 : }
13674 : else
13675 : {
13676 22 : if (nBandCount > nBands)
13677 : {
13678 1 : CPLError(CE_Failure, CPLE_AppDefined,
13679 : "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13680 1 : return CE_Failure;
13681 : }
13682 1057 : for (int i = 0; i < nBandCount; ++i)
13683 : {
13684 1038 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
13685 : {
13686 2 : CPLError(CE_Failure, CPLE_AppDefined,
13687 : "ComputeInterBandCovarianceMatrix(): invalid value "
13688 : "panBandList[%d] = %d",
13689 2 : i, panBandList[i]);
13690 2 : return CE_Failure;
13691 : }
13692 : }
13693 :
13694 19 : if (bWriteIntoMetadata)
13695 : {
13696 14 : bool bOK = nBandCount == nBands;
13697 38 : for (int i = 0; bOK && i < nBandCount; ++i)
13698 : {
13699 24 : bOK = (panBandList[i] == i + 1);
13700 : }
13701 14 : if (!bOK)
13702 : {
13703 4 : CPLError(CE_Failure, CPLE_AppDefined,
13704 : "ComputeInterBandCovarianceMatrix(): cannot write "
13705 : "STATISTICS_COVARIANCES metadata since the input band "
13706 : "list is not [1, 2, ... GetRasterCount()]");
13707 4 : return CE_Failure;
13708 : }
13709 : }
13710 : }
13711 :
13712 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13713 15 : if (nSize < nMatrixSize)
13714 : {
13715 0 : CPLError(CE_Failure, CPLE_AppDefined,
13716 : "ComputeInterBandCovarianceMatrix(): too small result matrix "
13717 : "provided");
13718 0 : return CE_Failure;
13719 : }
13720 :
13721 : // Find appropriate overview dataset
13722 15 : GDALDataset *poActiveDS = this;
13723 15 : if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13724 : {
13725 1 : GDALDataset *poOvrDS = nullptr;
13726 4 : for (int i = 0; i < nBandCount; ++i)
13727 : {
13728 3 : const int nIdxBand = panBandList[i] - 1;
13729 6 : auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13730 3 : GDALSTAT_APPROX_NUMSAMPLES);
13731 :
13732 6 : if (poOvrBand == papoBands[i] ||
13733 3 : poOvrBand->GetBand() != panBandList[i])
13734 : {
13735 0 : poOvrDS = nullptr;
13736 0 : break;
13737 : }
13738 3 : else if (i == 0)
13739 : {
13740 1 : if (poOvrBand->GetDataset() == this)
13741 : {
13742 0 : break;
13743 : }
13744 1 : poOvrDS = poOvrBand->GetDataset();
13745 : }
13746 2 : else if (poOvrBand->GetDataset() != poOvrDS)
13747 : {
13748 0 : poOvrDS = nullptr;
13749 0 : break;
13750 : }
13751 : }
13752 1 : if (poOvrDS)
13753 : {
13754 1 : poActiveDS = poOvrDS;
13755 : }
13756 : }
13757 :
13758 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13759 : const auto UseFloat32 = [](GDALDataType eDT)
13760 : {
13761 : return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13762 : eDT == GDT_Int16 || eDT == GDT_Float32;
13763 : };
13764 :
13765 : bool bUseFloat32 = UseFloat32(
13766 : poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13767 : for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13768 : {
13769 : bUseFloat32 = UseFloat32(
13770 : poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13771 : }
13772 : #endif
13773 :
13774 : CPLErr eErr =
13775 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13776 : bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13777 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13778 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13779 : pfnProgress, pProgressData)
13780 : :
13781 : #endif
13782 30 : ComputeInterBandCovarianceMatrixInternal<double>(
13783 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13784 15 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13785 : pfnProgress, pProgressData);
13786 :
13787 15 : if (bWriteIntoMetadata && eErr == CE_None)
13788 : {
13789 10 : CPLAssert(nBands == nBandCount);
13790 20 : std::string osStr;
13791 10 : size_t idx = 0;
13792 32 : for (int i = 0; i < nBands; ++i)
13793 : {
13794 22 : osStr.clear();
13795 74 : for (int j = 0; j < nBands; ++j, ++idx)
13796 : {
13797 52 : if (j > 0)
13798 30 : osStr += ',';
13799 52 : osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13800 : }
13801 22 : papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13802 22 : osStr.c_str());
13803 : }
13804 : }
13805 :
13806 15 : return eErr;
13807 : }
13808 :
13809 : /************************************************************************/
13810 : /* GDALDatasetComputeInterBandCovarianceMatrix() */
13811 : /************************************************************************/
13812 :
13813 : /**
13814 : \brief Compute the covariance matrix between bands of this dataset.
13815 :
13816 : The covariance indicates the level to which two bands vary together.
13817 :
13818 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13819 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13820 :
13821 : \f[
13822 : \mathrm{cov}[i,j] =
13823 : \frac{
13824 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13825 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13826 : }{
13827 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13828 : }
13829 : \f]
13830 :
13831 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13832 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13833 : is symmetric.
13834 :
13835 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13836 : if the pixels in bands are considered to be a sample of the whole population.
13837 : This is consistent with the default of
13838 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13839 : matrix is consistent with what can be obtained with
13840 :
13841 : \verbatim embed:rst
13842 : .. code-block:: python
13843 :
13844 : numpy.cov(
13845 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13846 : )
13847 : \endverbatim
13848 :
13849 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13850 : to be the whole population.
13851 :
13852 : The caller must provide an already allocated array in padfCovMatrix of size
13853 : at least GDALGetRasterCount() * GDALGetRasterCount().
13854 :
13855 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13856 : metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13857 : to use them.
13858 :
13859 : This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13860 :
13861 : @param hDS Dataset handle.
13862 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13863 : nBandCount * nBandCount.
13864 : @param nSize Number of elements in output array.
13865 : @param nBandCount Zero for all bands, or number of values in panBandList.
13866 : Defaults to 0.
13867 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13868 : nBandCount values such as panBandList[i] is the index
13869 : between 1 and GetRasterCount() of a band that must be used
13870 : in the covariance computation. Defaults to nullptr.
13871 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13872 : Defaults to false.
13873 : @param bWriteIntoMetadata Whether this method must write
13874 : STATISTICS_COVARIANCES band metadata items.
13875 : Defaults to true.
13876 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13877 : averaging phase of the covariance computation.
13878 : Defaults to 1.
13879 : @param pfnProgress a function to call to report progress, or NULL.
13880 : @param pProgressData application data to pass to the progress function.
13881 :
13882 : @return CE_None if successful, or CE_Failure in case of failure
13883 :
13884 : @since 3.13
13885 :
13886 : @see GDALDatasetGetInterBandCovarianceMatrix()
13887 : */
13888 17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13889 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13890 : const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13891 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13892 : void *pProgressData)
13893 : {
13894 17 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13895 17 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13896 17 : return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13897 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13898 17 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13899 : }
|