Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for raster file formats.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, 2003, Frank Warmerdam
9 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 :
16 : #include <array>
17 : #include <cassert>
18 : #include <climits>
19 : #include <cmath>
20 : #include <cstdarg>
21 : #include <cstdio>
22 : #include <cstdlib>
23 : #include <cstring>
24 : #include <algorithm>
25 : #include <limits>
26 : #include <map>
27 : #include <mutex>
28 : #include <new>
29 : #include <set>
30 : #include <string>
31 : #include <type_traits>
32 : #include <utility>
33 :
34 : #include "cpl_conv.h"
35 : #include "cpl_cpu_features.h"
36 : #include "cpl_error.h"
37 : #include "cpl_hash_set.h"
38 : #include "cpl_multiproc.h"
39 : #include "cpl_progress.h"
40 : #include "cpl_string.h"
41 : #include "cpl_vsi.h"
42 : #include "cpl_vsi_error.h"
43 :
44 : #include "gdal.h"
45 : #include "gdal_alg.h"
46 : #include "gdal_abstractbandblockcache.h"
47 : #include "gdalantirecursion.h"
48 : #include "gdal_dataset.h"
49 : #include "gdal_matrix.hpp"
50 :
51 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
52 : #include "gdal_matrix_avx2_fma.h"
53 : #endif
54 :
55 : #include "gdalsubdatasetinfo.h"
56 : #include "gdal_typetraits.h"
57 :
58 : #include "ogr_api.h"
59 : #include "ogr_attrind.h"
60 : #include "ogr_core.h"
61 : #include "ogr_feature.h"
62 : #include "ogr_featurestyle.h"
63 : #include "ogr_gensql.h"
64 : #include "ogr_geometry.h"
65 : #include "ogr_p.h"
66 : #include "ogr_spatialref.h"
67 : #include "ogr_srs_api.h"
68 : #include "ograpispy.h"
69 : #include "ogrsf_frmts.h"
70 : #include "ogrunionlayer.h"
71 : #include "ogr_swq.h"
72 : #include "memmultidim.h"
73 : #include "gdalmultidim_priv.h"
74 :
75 : #include "../frmts/derived/derivedlist.h"
76 :
77 : #ifdef SQLITE_ENABLED
78 : #include "../sqlite/ogrsqliteexecutesql.h"
79 : #endif
80 :
81 : #ifdef HAVE_OPENMP
82 : #include <omp.h>
83 : #endif
84 :
85 : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
86 :
87 : CPL_C_START
88 : GDALAsyncReader *GDALGetDefaultAsyncReader(GDALDataset *poDS, int nXOff,
89 : int nYOff, int nXSize, int nYSize,
90 : void *pBuf, int nBufXSize,
91 : int nBufYSize, GDALDataType eBufType,
92 : int nBandCount, int *panBandMap,
93 : int nPixelSpace, int nLineSpace,
94 : int nBandSpace, char **papszOptions);
95 : CPL_C_END
96 :
97 : enum class GDALAllowReadWriteMutexState
98 : {
99 : RW_MUTEX_STATE_UNKNOWN,
100 : RW_MUTEX_STATE_ALLOWED,
101 : RW_MUTEX_STATE_DISABLED
102 : };
103 :
104 : const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
105 : const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
106 :
107 : class GDALDataset::Private
108 : {
109 : CPL_DISALLOW_COPY_ASSIGN(Private)
110 :
111 : public:
112 : CPLMutex *hMutex = nullptr;
113 : std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
114 : #ifdef DEBUG_EXTRA
115 : std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
116 : #endif
117 : GDALAllowReadWriteMutexState eStateReadWriteMutex =
118 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
119 : int nCurrentLayerIdx = 0;
120 : int nLayerCount = -1;
121 : GIntBig nFeatureReadInLayer = 0;
122 : GIntBig nFeatureReadInDataset = 0;
123 : GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
124 : GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
125 : OGRLayer *poCurrentLayer = nullptr;
126 :
127 : std::mutex m_oMutexWKT{};
128 :
129 : char *m_pszWKTCached = nullptr;
130 : OGRSpatialReference *m_poSRSCached = nullptr;
131 : char *m_pszWKTGCPCached = nullptr;
132 : OGRSpatialReference *m_poSRSGCPCached = nullptr;
133 :
134 : GDALDataset *poParentDataset = nullptr;
135 :
136 : bool m_bOverviewsEnabled = true;
137 :
138 : std::vector<int>
139 : m_anBandMap{}; // used by RasterIO(). Values are 1, 2, etc.
140 :
141 181131 : Private() = default;
142 : };
143 :
144 : struct SharedDatasetCtxt
145 : {
146 : // PID of the thread that mark the dataset as shared
147 : // This may not be the actual PID, but the responsiblePID.
148 : GIntBig nPID;
149 : char *pszDescription;
150 : char *pszConcatenatedOpenOptions;
151 : int nOpenFlags;
152 :
153 : GDALDataset *poDS;
154 : };
155 :
156 : // Set of datasets opened as shared datasets (with GDALOpenShared)
157 : // The values in the set are of type SharedDatasetCtxt.
158 : static CPLHashSet *phSharedDatasetSet = nullptr;
159 :
160 : // Set of all datasets created in the constructor of GDALDataset.
161 : // In the case of a shared dataset, memorize the PID of the thread
162 : // that marked the dataset as shared, so that we can remove it from
163 : // the phSharedDatasetSet in the destructor of the dataset, even
164 : // if GDALClose is called from a different thread.
165 : static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
166 :
167 : static CPLMutex *hDLMutex = nullptr;
168 :
169 : // Static array of all datasets. Used by GDALGetOpenDatasets.
170 : // Not thread-safe. See GDALGetOpenDatasets.
171 : static GDALDataset **ppDatasets = nullptr;
172 :
173 8438 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
174 : {
175 8438 : const SharedDatasetCtxt *psStruct =
176 : static_cast<const SharedDatasetCtxt *>(elt);
177 : return static_cast<unsigned long>(
178 8438 : CPLHashSetHashStr(psStruct->pszDescription) ^
179 8438 : CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
180 8438 : psStruct->nOpenFlags ^ psStruct->nPID);
181 : }
182 :
183 7025 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
184 : {
185 7025 : const SharedDatasetCtxt *psStruct1 =
186 : static_cast<const SharedDatasetCtxt *>(elt1);
187 7025 : const SharedDatasetCtxt *psStruct2 =
188 : static_cast<const SharedDatasetCtxt *>(elt2);
189 13952 : return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
190 6927 : strcmp(psStruct1->pszConcatenatedOpenOptions,
191 6927 : psStruct2->pszConcatenatedOpenOptions) == 0 &&
192 20879 : psStruct1->nPID == psStruct2->nPID &&
193 13952 : psStruct1->nOpenFlags == psStruct2->nOpenFlags;
194 : }
195 :
196 411 : static void GDALSharedDatasetFreeFunc(void *elt)
197 : {
198 411 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
199 411 : CPLFree(psStruct->pszDescription);
200 411 : CPLFree(psStruct->pszConcatenatedOpenOptions);
201 411 : CPLFree(psStruct);
202 411 : }
203 :
204 : static std::string
205 7067 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
206 : {
207 7067 : std::string osStr;
208 7080 : for (const char *pszOption : cpl::Iterate(papszOpenOptions))
209 13 : osStr += pszOption;
210 7067 : return osStr;
211 : }
212 :
213 : /************************************************************************/
214 : /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
215 : /************************************************************************/
216 :
217 : // The open-shared mutex must be used by the ProxyPool too.
218 483423 : CPLMutex **GDALGetphDLMutex()
219 : {
220 483423 : return &hDLMutex;
221 : }
222 :
223 : // The current thread will act in the behalf of the thread of PID
224 : // responsiblePID.
225 472840 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
226 : {
227 : GIntBig *pResponsiblePID =
228 472840 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
229 472840 : if (pResponsiblePID == nullptr)
230 : {
231 228 : pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
232 228 : CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
233 : }
234 472840 : *pResponsiblePID = responsiblePID;
235 472840 : }
236 :
237 : // Get the PID of the thread that the current thread will act in the behalf of
238 : // By default : the current thread acts in the behalf of itself.
239 602229 : GIntBig GDALGetResponsiblePIDForCurrentThread()
240 : {
241 : GIntBig *pResponsiblePID =
242 602229 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
243 602229 : if (pResponsiblePID == nullptr)
244 44633 : return CPLGetPID();
245 557596 : return *pResponsiblePID;
246 : }
247 :
248 : /************************************************************************/
249 : /* ==================================================================== */
250 : /* GDALDataset */
251 : /* ==================================================================== */
252 : /************************************************************************/
253 :
254 : /**
255 : * \class GDALDataset "gdal_priv.h"
256 : *
257 : * A dataset encapsulating one or more raster bands. Details are further
258 : * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
259 : * Raster Data Model</a>.
260 : *
261 : * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
262 : * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
263 : * dataset.
264 : */
265 :
266 : /************************************************************************/
267 : /* GDALDataset() */
268 : /************************************************************************/
269 :
270 : //! @cond Doxygen_Suppress
271 160144 : GDALDataset::GDALDataset()
272 160144 : : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
273 : {
274 160144 : }
275 :
276 181131 : GDALDataset::GDALDataset(int bForceCachedIOIn)
277 181131 : : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
278 181131 : m_poPrivate(new(std::nothrow) GDALDataset::Private)
279 : {
280 181131 : }
281 :
282 : //! @endcond
283 :
284 : /************************************************************************/
285 : /* ~GDALDataset() */
286 : /************************************************************************/
287 :
288 : /**
289 : * \brief Destroy an open GDALDataset.
290 : *
291 : * This is the accepted method of closing a GDAL dataset and deallocating
292 : * all resources associated with it.
293 : *
294 : * Equivalent of the C callable GDALClose(). Except that GDALClose() first
295 : * decrements the reference count, and then closes only if it has dropped to
296 : * zero.
297 : *
298 : * For Windows users, it is not recommended to use the delete operator on the
299 : * dataset object because of known issues when allocating and freeing memory
300 : * across module boundaries. Calling GDALClose() is then a better option.
301 : */
302 :
303 181112 : GDALDataset::~GDALDataset()
304 :
305 : {
306 : // we don't want to report destruction of datasets that
307 : // were never really open or meant as internal
308 181112 : if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
309 : {
310 72528 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
311 209 : CPLDebug("GDAL",
312 : "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
313 209 : GetDescription(), this, static_cast<int>(CPLGetPID()),
314 209 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
315 : else
316 72319 : CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
317 : }
318 :
319 181112 : GDALDataset::Close();
320 :
321 : /* -------------------------------------------------------------------- */
322 : /* Remove dataset from the "open" dataset list. */
323 : /* -------------------------------------------------------------------- */
324 181112 : if (!bIsInternal)
325 : {
326 147882 : CPLMutexHolderD(&hDLMutex);
327 73941 : if (poAllDatasetMap)
328 : {
329 : std::map<GDALDataset *, GIntBig>::iterator oIter =
330 73941 : poAllDatasetMap->find(this);
331 73941 : CPLAssert(oIter != poAllDatasetMap->end());
332 :
333 73941 : UnregisterFromSharedDataset();
334 :
335 73941 : poAllDatasetMap->erase(oIter);
336 :
337 73941 : if (poAllDatasetMap->empty())
338 : {
339 30693 : delete poAllDatasetMap;
340 30693 : poAllDatasetMap = nullptr;
341 30693 : if (phSharedDatasetSet)
342 : {
343 275 : CPLHashSetDestroy(phSharedDatasetSet);
344 : }
345 30693 : phSharedDatasetSet = nullptr;
346 30693 : CPLFree(ppDatasets);
347 30693 : ppDatasets = nullptr;
348 : }
349 : }
350 : }
351 :
352 : /* -------------------------------------------------------------------- */
353 : /* Destroy the raster bands if they exist. */
354 : /* -------------------------------------------------------------------- */
355 1716030 : for (int i = 0; i < nBands && papoBands != nullptr; ++i)
356 : {
357 1534920 : if (papoBands[i] != nullptr)
358 1534920 : delete papoBands[i];
359 1534920 : papoBands[i] = nullptr;
360 : }
361 :
362 181112 : CPLFree(papoBands);
363 :
364 181112 : if (m_poStyleTable)
365 : {
366 23 : delete m_poStyleTable;
367 23 : m_poStyleTable = nullptr;
368 : }
369 :
370 181112 : if (m_poPrivate != nullptr)
371 : {
372 181112 : if (m_poPrivate->hMutex != nullptr)
373 21293 : CPLDestroyMutex(m_poPrivate->hMutex);
374 :
375 : #if defined(__COVERITY__) || defined(DEBUG)
376 : // Not needed since at destruction there is no risk of concurrent use.
377 362224 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
378 : #endif
379 181112 : CPLFree(m_poPrivate->m_pszWKTCached);
380 181112 : if (m_poPrivate->m_poSRSCached)
381 : {
382 0 : m_poPrivate->m_poSRSCached->Release();
383 : }
384 181112 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
385 181112 : if (m_poPrivate->m_poSRSGCPCached)
386 : {
387 0 : m_poPrivate->m_poSRSGCPCached->Release();
388 : }
389 : }
390 :
391 181112 : delete m_poPrivate;
392 :
393 181112 : CSLDestroy(papszOpenOptions);
394 181112 : }
395 :
396 : /************************************************************************/
397 : /* Close() */
398 : /************************************************************************/
399 :
400 : /** Do final cleanup before a dataset is destroyed.
401 : *
402 : * This method is typically called by GDALClose() or the destructor of a
403 : * GDALDataset subclass. It might also be called by C++ users before
404 : * destroying a dataset. It should not be called on a shared dataset whose
405 : * reference count is greater than one.
406 : *
407 : * It gives a last chance to the closing process to return an error code if
408 : * something goes wrong, in particular in creation / update scenarios where
409 : * file write or network communication might occur when finalizing the dataset.
410 : *
411 : * Implementations should be robust to this method to be called several times
412 : * (on subsequent calls, it should do nothing and return CE_None).
413 : * Once it has been called, no other method than Close() or the dataset
414 : * destructor should be called. RasterBand or OGRLayer owned by the dataset
415 : * should be assumed as no longer being valid.
416 : *
417 : * If a driver implements this method, it must also call it from its
418 : * dataset destructor.
419 : *
420 : * Starting with GDAL 3.13, this function may report progress if a progress
421 : * callback if provided in the pfnProgress argument and if the dataset returns
422 : * true for GDALDataset::GetCloseReportsProgress()
423 : *
424 : * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
425 : * or GDALDatasetRunCloseWithoutDestroyingEx()
426 : *
427 : * A typical implementation might look as the following
428 : * \code{.cpp}
429 : *
430 : * MyDataset::~MyDataset()
431 : * {
432 : * try
433 : * {
434 : * MyDataset::Close();
435 : * }
436 : * catch (const std::exception &exc)
437 : * {
438 : * // If Close() can throw exception
439 : * CPLError(CE_Failure, CPLE_AppDefined,
440 : * "Exception thrown in MyDataset::Close(): %s",
441 : * exc.what());
442 : * }
443 : * catch (...)
444 : * {
445 : * // If Close() can throw exception
446 : * CPLError(CE_Failure, CPLE_AppDefined,
447 : * "Exception thrown in MyDataset::Close()");
448 : * }
449 : * }
450 : *
451 : * CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
452 : * {
453 : * CPLErr eErr = CE_None;
454 : * if( nOpenFlags != OPEN_FLAGS_CLOSED )
455 : * {
456 : * eErr = MyDataset::FlushCache(true);
457 : *
458 : * // Do something driver specific
459 : * if (m_fpImage)
460 : * {
461 : * if( VSIFCloseL(m_fpImage) != 0 )
462 : * {
463 : * CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
464 : * eErr = CE_Failure;
465 : * }
466 : * }
467 : *
468 : * // Call parent Close() implementation.
469 : * eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
470 : * }
471 : * return eErr;
472 : * }
473 : * \endcode
474 : *
475 : * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
476 : * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
477 : * @return CE_None if no error
478 : *
479 : * @since GDAL 3.7
480 : */
481 296124 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
482 : {
483 : (void)pfnProgress;
484 : (void)pProgressData;
485 :
486 296124 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
487 : {
488 : // Call UnregisterFromSharedDataset() before altering nOpenFlags
489 181112 : UnregisterFromSharedDataset();
490 :
491 181112 : nOpenFlags = OPEN_FLAGS_CLOSED;
492 : }
493 :
494 296124 : if (IsMarkedSuppressOnClose())
495 : {
496 3450 : if (poDriver == nullptr ||
497 : // Someone issuing Create("foo.tif") on a
498 : // memory driver doesn't expect files with those names to be deleted
499 : // on a file system...
500 : // This is somewhat messy. Ideally there should be a way for the
501 : // driver to overload the default behavior
502 1681 : (!EQUAL(poDriver->GetDescription(), "MEM") &&
503 1603 : !EQUAL(poDriver->GetDescription(), "Memory")))
504 : {
505 1691 : if (VSIUnlink(GetDescription()) == 0)
506 683 : UnMarkSuppressOnClose();
507 : }
508 : }
509 :
510 296124 : return CE_None;
511 : }
512 :
513 : /************************************************************************/
514 : /* GDALDatasetRunCloseWithoutDestroying() */
515 : /************************************************************************/
516 :
517 : /** Run the Close() method, without running destruction of the object.
518 : *
519 : * This ensures that content that should be written to file is written and
520 : * that all file descriptors are closed.
521 : *
522 : * Note that this is different from GDALClose() which also destroys
523 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
524 : * the only functions that can be safely called on the dataset handle after
525 : * this function has been called.
526 : *
527 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
528 : * this function.
529 : *
530 : * This function is equivalent to the C++ method GDALDataset:Close()
531 : *
532 : * @param hDS dataset handle.
533 : * @return CE_None if no error
534 : *
535 : * @since GDAL 3.12
536 : * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
537 : */
538 0 : CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
539 : {
540 0 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
541 0 : return GDALDataset::FromHandle(hDS)->Close();
542 : }
543 :
544 : /************************************************************************/
545 : /* GDALDatasetRunCloseWithoutDestroyingEx() */
546 : /************************************************************************/
547 :
548 : /** Run the Close() method, without running destruction of the object.
549 : *
550 : * This ensures that content that should be written to file is written and
551 : * that all file descriptors are closed.
552 : *
553 : * Note that this is different from GDALClose() which also destroys
554 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
555 : * the only functions that can be safely called on the dataset handle after
556 : * this function has been called.
557 : *
558 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
559 : * this function.
560 : *
561 : * This function may report progress if a progress
562 : * callback if provided in the pfnProgress argument and if the dataset returns
563 : * true for GDALDataset::GetCloseReportsProgress()
564 : *
565 : * This function is equivalent to the C++ method GDALDataset:Close()
566 : *
567 : * @param hDS dataset handle.
568 : * @param pfnProgress Progress callback, or nullptr
569 : * @param pProgressData User data of progress callback, or nullptr
570 : *
571 : * @return CE_None if no error
572 : *
573 : * @since GDAL 3.13
574 : * @see GDALClose()
575 : */
576 12 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
577 : GDALProgressFunc pfnProgress,
578 : void *pProgressData)
579 : {
580 12 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
581 12 : return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
582 : }
583 :
584 : /************************************************************************/
585 : /* GetCloseReportsProgress() */
586 : /************************************************************************/
587 :
588 : /** Returns whether the Close() operation will report progress / is a potential
589 : * lengthy operation.
590 : *
591 : * At time of writing, only the COG driver will return true, if the dataset
592 : * has been created through the GDALDriver::Create() interface.
593 : *
594 : * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
595 : *
596 : * @return true if the Close() operation will report progress
597 : * @since GDAL 3.13
598 : * @see Close()
599 : */
600 213 : bool GDALDataset::GetCloseReportsProgress() const
601 : {
602 213 : return false;
603 : }
604 :
605 : /************************************************************************/
606 : /* GDALDatasetGetCloseReportsProgress() */
607 : /************************************************************************/
608 :
609 : /** Returns whether the Close() operation will report progress / is a potential
610 : * lengthy operation.
611 : *
612 : * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
613 : *
614 : * @param hDS dataset handle.
615 : * @return CE_None if no error
616 : *
617 : * @return true if the Close() operation will report progress
618 : * @since GDAL 3.13
619 : * @see GDALClose()
620 : */
621 2 : bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
622 : {
623 2 : VALIDATE_POINTER1(hDS, __func__, false);
624 2 : return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
625 : }
626 :
627 : /************************************************************************/
628 : /* CanReopenWithCurrentDescription() */
629 : /************************************************************************/
630 :
631 : /** Returns whether, once this dataset is closed, it can be re-opened with
632 : * Open() using the current value of GetDescription()
633 : *
634 : * The default implementation returns true. Some drivers, like MVT in Create()
635 : * mode, can return false. Some drivers return true, but the re-opened dataset
636 : * may be opened by another driver (e.g. the COG driver will return true, but
637 : * the driver used for re-opening is GTiff).
638 : *
639 : * @return true if the dataset can be re-opened using the value as
640 : * GetDescription() as connection string for Open()
641 : * @since GDAL 3.13
642 : */
643 2 : bool GDALDataset::CanReopenWithCurrentDescription() const
644 : {
645 2 : return true;
646 : }
647 :
648 : /************************************************************************/
649 : /* UnregisterFromSharedDataset() */
650 : /************************************************************************/
651 :
652 255053 : void GDALDataset::UnregisterFromSharedDataset()
653 : {
654 255053 : if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
655 254642 : return;
656 :
657 822 : CPLMutexHolderD(&hDLMutex);
658 :
659 : std::map<GDALDataset *, GIntBig>::iterator oIter =
660 411 : poAllDatasetMap->find(this);
661 411 : CPLAssert(oIter != poAllDatasetMap->end());
662 411 : const GIntBig nPIDCreatorForShared = oIter->second;
663 411 : bShared = false;
664 : SharedDatasetCtxt sStruct;
665 411 : sStruct.nPID = nPIDCreatorForShared;
666 411 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
667 411 : sStruct.pszDescription = const_cast<char *>(GetDescription());
668 : std::string osConcatenatedOpenOptions =
669 822 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
670 411 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
671 411 : sStruct.poDS = nullptr;
672 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
673 411 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
674 411 : if (psStruct && psStruct->poDS == this)
675 : {
676 410 : CPLHashSetRemove(phSharedDatasetSet, psStruct);
677 : }
678 : else
679 : {
680 1 : CPLDebug("GDAL",
681 : "Should not happen. Cannot find %s, "
682 : "this=%p in phSharedDatasetSet",
683 1 : GetDescription(), this);
684 : }
685 : }
686 :
687 : /************************************************************************/
688 : /* AddToDatasetOpenList() */
689 : /************************************************************************/
690 :
691 75274 : void GDALDataset::AddToDatasetOpenList()
692 : {
693 : /* -------------------------------------------------------------------- */
694 : /* Add this dataset to the open dataset list. */
695 : /* -------------------------------------------------------------------- */
696 75274 : bIsInternal = false;
697 :
698 75274 : CPLMutexHolderD(&hDLMutex);
699 :
700 75274 : if (poAllDatasetMap == nullptr)
701 30703 : poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
702 75274 : (*poAllDatasetMap)[this] = -1;
703 75274 : }
704 :
705 : /************************************************************************/
706 : /* FlushCache() */
707 : /************************************************************************/
708 :
709 : /**
710 : * \brief Flush all write cached data to disk.
711 : *
712 : * Any raster (or other GDAL) data written via GDAL calls, but buffered
713 : * internally will be written to disk.
714 : *
715 : * The default implementation of this method just calls the FlushCache() method
716 : * on each of the raster bands and the SyncToDisk() method
717 : * on each of the layers. Conceptually, calling FlushCache() on a dataset
718 : * should include any work that might be accomplished by calling SyncToDisk()
719 : * on layers in that dataset.
720 : *
721 : * Using this method does not prevent use from calling GDALClose()
722 : * to properly close a dataset and ensure that important data not addressed
723 : * by FlushCache() is written in the file.
724 : *
725 : * This method is the same as the C function GDALFlushCache().
726 : *
727 : * @param bAtClosing Whether this is called from a GDALDataset destructor
728 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
729 : */
730 :
731 120789 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
732 :
733 : {
734 120789 : CPLErr eErr = CE_None;
735 : // This sometimes happens if a dataset is destroyed before completely
736 : // built.
737 :
738 120789 : if (papoBands)
739 : {
740 1936310 : for (int i = 0; i < nBands; ++i)
741 : {
742 1829450 : if (papoBands[i])
743 : {
744 1829450 : if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
745 7 : eErr = CE_Failure;
746 : }
747 : }
748 : }
749 :
750 120789 : const int nLayers = GetLayerCount();
751 : // cppcheck-suppress knownConditionTrueFalse
752 120789 : if (nLayers > 0)
753 : {
754 16746 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
755 26148 : for (int i = 0; i < nLayers; ++i)
756 : {
757 17775 : OGRLayer *poLayer = GetLayer(i);
758 :
759 17775 : if (poLayer)
760 : {
761 17775 : if (poLayer->SyncToDisk() != OGRERR_NONE)
762 1 : eErr = CE_Failure;
763 : }
764 : }
765 : }
766 :
767 120789 : return eErr;
768 : }
769 :
770 : /************************************************************************/
771 : /* GDALFlushCache() */
772 : /************************************************************************/
773 :
774 : /**
775 : * \brief Flush all write cached data to disk.
776 : *
777 : * @see GDALDataset::FlushCache().
778 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
779 : */
780 :
781 5055 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
782 :
783 : {
784 5055 : VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
785 :
786 5055 : return GDALDataset::FromHandle(hDS)->FlushCache(false);
787 : }
788 :
789 : /************************************************************************/
790 : /* DropCache() */
791 : /************************************************************************/
792 :
793 : /**
794 : * \brief Drop all write cached data
795 : *
796 : * This method is the same as the C function GDALDropCache().
797 : *
798 : * @return CE_None in case of success
799 : * @since 3.9
800 : */
801 :
802 1 : CPLErr GDALDataset::DropCache()
803 :
804 : {
805 1 : CPLErr eErr = CE_None;
806 :
807 1 : if (papoBands)
808 : {
809 2 : for (int i = 0; i < nBands; ++i)
810 : {
811 1 : if (papoBands[i])
812 : {
813 1 : if (papoBands[i]->DropCache() != CE_None)
814 0 : eErr = CE_Failure;
815 : }
816 : }
817 : }
818 :
819 1 : return eErr;
820 : }
821 :
822 : /************************************************************************/
823 : /* GDALDropCache() */
824 : /************************************************************************/
825 :
826 : /**
827 : * \brief Drop all write cached data
828 : *
829 : * @see GDALDataset::DropCache().
830 : * @return CE_None in case of success
831 : * @since 3.9
832 : */
833 :
834 0 : CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
835 :
836 : {
837 0 : VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
838 :
839 0 : return GDALDataset::FromHandle(hDS)->DropCache();
840 : }
841 :
842 : /************************************************************************/
843 : /* GetEstimatedRAMUsage() */
844 : /************************************************************************/
845 :
846 : /**
847 : * \brief Return the intrinsic RAM usage of this dataset.
848 : *
849 : * The returned value should take into account caches in the underlying driver
850 : * and decoding library, but not the usage related to the GDAL block cache.
851 : *
852 : * At time of writing, this method is only implemented in the JP2OpenJPEG
853 : * driver. For single-tiled JPEG2000 images, the decoding of the image,
854 : * even partially, involves allocating at least
855 : * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
856 : * library.
857 : *
858 : * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
859 : * driver, to determine how long a dataset in the pool must be kept open, given
860 : * the RAM usage of the dataset with respect to the usable total RAM.
861 : *
862 : * @since GDAL 3.7
863 : * @return RAM usage in bytes, or -1 if unknown (the default implementation
864 : * returns -1)
865 : */
866 :
867 3338 : GIntBig GDALDataset::GetEstimatedRAMUsage()
868 : {
869 3338 : return -1;
870 : }
871 :
872 : /************************************************************************/
873 : /* BlockBasedFlushCache() */
874 : /* */
875 : /* This helper method can be called by the */
876 : /* GDALDataset::FlushCache() for particular drivers to ensure */
877 : /* that buffers will be flushed in a manner suitable for pixel */
878 : /* interleaved (by block) IO. That is, if all the bands have */
879 : /* the same size blocks then a given block will be flushed for */
880 : /* all bands before proceeding to the next block. */
881 : /************************************************************************/
882 :
883 : //! @cond Doxygen_Suppress
884 350 : CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
885 :
886 : {
887 350 : GDALRasterBand *poBand1 = GetRasterBand(1);
888 350 : if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
889 : {
890 7 : return GDALDataset::FlushCache(bAtClosing);
891 : }
892 :
893 343 : int nBlockXSize = 0;
894 343 : int nBlockYSize = 0;
895 343 : poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
896 :
897 : /* -------------------------------------------------------------------- */
898 : /* Verify that all bands match. */
899 : /* -------------------------------------------------------------------- */
900 1108 : for (int iBand = 1; iBand < nBands; ++iBand)
901 : {
902 765 : GDALRasterBand *poBand = GetRasterBand(iBand + 1);
903 :
904 : int nThisBlockXSize, nThisBlockYSize;
905 765 : poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
906 765 : if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
907 : {
908 0 : return GDALDataset::FlushCache(bAtClosing);
909 : }
910 : }
911 :
912 : /* -------------------------------------------------------------------- */
913 : /* Now flush writable data. */
914 : /* -------------------------------------------------------------------- */
915 794 : for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
916 : {
917 991 : for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
918 : {
919 1690 : for (int iBand = 0; iBand < nBands; ++iBand)
920 : {
921 1150 : const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
922 :
923 1150 : if (eErr != CE_None)
924 0 : return CE_Failure;
925 : }
926 : }
927 : }
928 343 : return CE_None;
929 : }
930 :
931 : /************************************************************************/
932 : /* RasterInitialize() */
933 : /* */
934 : /* Initialize raster size */
935 : /************************************************************************/
936 :
937 0 : void GDALDataset::RasterInitialize(int nXSize, int nYSize)
938 :
939 : {
940 0 : CPLAssert(nXSize > 0 && nYSize > 0);
941 :
942 0 : nRasterXSize = nXSize;
943 0 : nRasterYSize = nYSize;
944 0 : }
945 :
946 : //! @endcond
947 :
948 : /************************************************************************/
949 : /* AddBand() */
950 : /************************************************************************/
951 :
952 : /**
953 : * \fn GDALDataset::AddBand(GDALDataType, char**)
954 : * \brief Add a band to a dataset.
955 : *
956 : * This method will add a new band to the dataset if the underlying format
957 : * supports this action. Most formats do not.
958 : *
959 : * Note that the new GDALRasterBand is not returned. It may be fetched
960 : * after successful completion of the method by calling
961 : * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
962 : * band will always be the last band.
963 : *
964 : * @param eType the data type of the pixels in the new band.
965 : *
966 : * @param papszOptions a list of NAME=VALUE option strings. The supported
967 : * options are format specific. NULL may be passed by default.
968 : *
969 : * @return CE_None on success or CE_Failure on failure.
970 : */
971 :
972 0 : CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
973 : CPL_UNUSED char **papszOptions)
974 :
975 : {
976 0 : ReportError(CE_Failure, CPLE_NotSupported,
977 : "Dataset does not support the AddBand() method.");
978 :
979 0 : return CE_Failure;
980 : }
981 :
982 : /************************************************************************/
983 : /* GDALAddBand() */
984 : /************************************************************************/
985 :
986 : /**
987 : * \brief Add a band to a dataset.
988 : *
989 : * @see GDALDataset::AddBand().
990 : */
991 :
992 32 : CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
993 : CSLConstList papszOptions)
994 :
995 : {
996 32 : VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
997 :
998 64 : return GDALDataset::FromHandle(hDataset)->AddBand(
999 32 : eType, const_cast<char **>(papszOptions));
1000 : }
1001 :
1002 : /************************************************************************/
1003 : /* SetBand() */
1004 : /************************************************************************/
1005 :
1006 : //! @cond Doxygen_Suppress
1007 : /** Set a band in the band array, updating the band count, and array size
1008 : * appropriately.
1009 : *
1010 : * @param nNewBand new band number (indexing starts at 1)
1011 : * @param poBand band object.
1012 : */
1013 :
1014 1680260 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1015 :
1016 : {
1017 : /* -------------------------------------------------------------------- */
1018 : /* Do we need to grow the bands list? */
1019 : /* -------------------------------------------------------------------- */
1020 1680260 : if (nBands < nNewBand || papoBands == nullptr)
1021 : {
1022 945092 : GDALRasterBand **papoNewBands = nullptr;
1023 :
1024 945092 : if (papoBands == nullptr)
1025 97851 : papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1026 97851 : sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1027 : else
1028 : papoNewBands = static_cast<GDALRasterBand **>(
1029 847241 : VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1030 847241 : std::max(nNewBand, nBands)));
1031 945092 : if (papoNewBands == nullptr)
1032 : {
1033 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1034 : "Cannot allocate band array");
1035 0 : return;
1036 : }
1037 :
1038 945092 : papoBands = papoNewBands;
1039 :
1040 1838970 : for (int i = nBands; i < nNewBand; ++i)
1041 893880 : papoBands[i] = nullptr;
1042 :
1043 945092 : nBands = std::max(nBands, nNewBand);
1044 :
1045 945092 : if (m_poPrivate)
1046 : {
1047 945092 : for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1048 2625350 : i < nBands; ++i)
1049 : {
1050 1680260 : m_poPrivate->m_anBandMap.push_back(i + 1);
1051 : }
1052 : }
1053 : }
1054 :
1055 : /* -------------------------------------------------------------------- */
1056 : /* Set the band. Resetting the band is currently not permitted. */
1057 : /* -------------------------------------------------------------------- */
1058 1680260 : if (papoBands[nNewBand - 1] != nullptr)
1059 : {
1060 0 : ReportError(CE_Failure, CPLE_NotSupported,
1061 : "Cannot set band %d as it is already set", nNewBand);
1062 0 : return;
1063 : }
1064 :
1065 1680260 : papoBands[nNewBand - 1] = poBand;
1066 :
1067 : /* -------------------------------------------------------------------- */
1068 : /* Set back reference information on the raster band. Note */
1069 : /* that the GDALDataset is a friend of the GDALRasterBand */
1070 : /* specifically to allow this. */
1071 : /* -------------------------------------------------------------------- */
1072 1680260 : poBand->nBand = nNewBand;
1073 1680260 : poBand->poDS = this;
1074 1680260 : poBand->nRasterXSize = nRasterXSize;
1075 1680260 : poBand->nRasterYSize = nRasterYSize;
1076 1680260 : poBand->eAccess = eAccess; // Default access to be same as dataset.
1077 : }
1078 :
1079 : //! @endcond
1080 :
1081 : /************************************************************************/
1082 : /* SetBand() */
1083 : /************************************************************************/
1084 :
1085 : //! @cond Doxygen_Suppress
1086 : /** Set a band in the band array, updating the band count, and array size
1087 : * appropriately.
1088 : *
1089 : * @param nNewBand new band number (indexing starts at 1)
1090 : * @param poBand band object.
1091 : */
1092 :
1093 1109450 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1094 : {
1095 1109450 : SetBand(nNewBand, poBand.release());
1096 1109450 : }
1097 :
1098 : //! @endcond
1099 :
1100 : /************************************************************************/
1101 : /* GetRasterXSize() */
1102 : /************************************************************************/
1103 :
1104 : /**
1105 :
1106 : \brief Fetch raster width in pixels.
1107 :
1108 : Equivalent of the C function GDALGetRasterXSize().
1109 :
1110 : @return the width in pixels of raster bands in this GDALDataset.
1111 :
1112 : */
1113 :
1114 713628 : int GDALDataset::GetRasterXSize() const
1115 : {
1116 713628 : return nRasterXSize;
1117 : }
1118 :
1119 : /************************************************************************/
1120 : /* GDALGetRasterXSize() */
1121 : /************************************************************************/
1122 :
1123 : /**
1124 : * \brief Fetch raster width in pixels.
1125 : *
1126 : * @see GDALDataset::GetRasterXSize().
1127 : */
1128 :
1129 37790 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1130 :
1131 : {
1132 37790 : VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1133 :
1134 37790 : return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
1135 : }
1136 :
1137 : /************************************************************************/
1138 : /* GetRasterYSize() */
1139 : /************************************************************************/
1140 :
1141 : /**
1142 :
1143 : \brief Fetch raster height in pixels.
1144 :
1145 : Equivalent of the C function GDALGetRasterYSize().
1146 :
1147 : @return the height in pixels of raster bands in this GDALDataset.
1148 :
1149 : */
1150 :
1151 604431 : int GDALDataset::GetRasterYSize() const
1152 : {
1153 604431 : return nRasterYSize;
1154 : }
1155 :
1156 : /************************************************************************/
1157 : /* GDALGetRasterYSize() */
1158 : /************************************************************************/
1159 :
1160 : /**
1161 : * \brief Fetch raster height in pixels.
1162 : *
1163 : * @see GDALDataset::GetRasterYSize().
1164 : */
1165 :
1166 37402 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1167 :
1168 : {
1169 37402 : VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1170 :
1171 37402 : return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
1172 : }
1173 :
1174 : /************************************************************************/
1175 : /* GetRasterBand() */
1176 : /************************************************************************/
1177 :
1178 : /**
1179 :
1180 : \brief Fetch a band object for a dataset.
1181 :
1182 : See GetBands() for a C++ iterator version of this method.
1183 :
1184 : Equivalent of the C function GDALGetRasterBand().
1185 :
1186 : @param nBandId the index number of the band to fetch, from 1 to
1187 : GetRasterCount().
1188 :
1189 : @return the nBandId th band object
1190 :
1191 : */
1192 :
1193 12576500 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1194 :
1195 : {
1196 12576500 : if (papoBands)
1197 : {
1198 12576500 : if (nBandId < 1 || nBandId > nBands)
1199 : {
1200 12 : ReportError(CE_Failure, CPLE_IllegalArg,
1201 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1202 : nBandId);
1203 12 : return nullptr;
1204 : }
1205 :
1206 12576500 : return papoBands[nBandId - 1];
1207 : }
1208 13 : return nullptr;
1209 : }
1210 :
1211 : /************************************************************************/
1212 : /* GetRasterBand() */
1213 : /************************************************************************/
1214 :
1215 : /**
1216 :
1217 : \brief Fetch a band object for a dataset.
1218 :
1219 : See GetBands() for a C++ iterator version of this method.
1220 :
1221 : Equivalent of the C function GDALGetRasterBand().
1222 :
1223 : @param nBandId the index number of the band to fetch, from 1 to
1224 : GetRasterCount().
1225 :
1226 : @return the nBandId th band object
1227 :
1228 : */
1229 :
1230 594 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1231 :
1232 : {
1233 594 : if (papoBands)
1234 : {
1235 594 : if (nBandId < 1 || nBandId > nBands)
1236 : {
1237 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1238 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1239 : nBandId);
1240 0 : return nullptr;
1241 : }
1242 :
1243 594 : return papoBands[nBandId - 1];
1244 : }
1245 0 : return nullptr;
1246 : }
1247 :
1248 : /************************************************************************/
1249 : /* GDALGetRasterBand() */
1250 : /************************************************************************/
1251 :
1252 : /**
1253 : * \brief Fetch a band object for a dataset.
1254 : * @see GDALDataset::GetRasterBand().
1255 : */
1256 :
1257 403285 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1258 :
1259 : {
1260 403285 : VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1261 :
1262 403285 : return GDALRasterBand::ToHandle(
1263 403285 : GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
1264 : }
1265 :
1266 : /************************************************************************/
1267 : /* GetRasterCount() */
1268 : /************************************************************************/
1269 :
1270 : /**
1271 : * \brief Fetch the number of raster bands on this dataset.
1272 : *
1273 : * Same as the C function GDALGetRasterCount().
1274 : *
1275 : * @return the number of raster bands.
1276 : */
1277 :
1278 6425770 : int GDALDataset::GetRasterCount() const
1279 : {
1280 6425770 : return papoBands ? nBands : 0;
1281 : }
1282 :
1283 : /************************************************************************/
1284 : /* GDALGetRasterCount() */
1285 : /************************************************************************/
1286 :
1287 : /**
1288 : * \brief Fetch the number of raster bands on this dataset.
1289 : *
1290 : * @see GDALDataset::GetRasterCount().
1291 : */
1292 :
1293 383257 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1294 :
1295 : {
1296 383257 : VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1297 :
1298 383257 : return GDALDataset::FromHandle(hDS)->GetRasterCount();
1299 : }
1300 :
1301 : /************************************************************************/
1302 : /* GetProjectionRef() */
1303 : /************************************************************************/
1304 :
1305 : /**
1306 : * \brief Fetch the projection definition string for this dataset.
1307 : *
1308 : * Same as the C function GDALGetProjectionRef().
1309 : *
1310 : * The returned string defines the projection coordinate system of the
1311 : * image in OpenGIS WKT format. It should be suitable for use with the
1312 : * OGRSpatialReference class.
1313 : *
1314 : * When a projection definition is not available an empty (but not NULL)
1315 : * string is returned.
1316 : *
1317 : * \note Starting with GDAL 3.0, this is a compatibility layer around
1318 : * GetSpatialRef()
1319 : *
1320 : * @return a pointer to an internal projection reference string. It should
1321 : * not be altered, freed or expected to last for long.
1322 : *
1323 : * @see https://gdal.org/tutorials/osr_api_tut.html
1324 : */
1325 :
1326 5409 : const char *GDALDataset::GetProjectionRef() const
1327 : {
1328 5409 : const auto poSRS = GetSpatialRef();
1329 5409 : if (!poSRS || !m_poPrivate)
1330 : {
1331 2429 : return "";
1332 : }
1333 2980 : char *pszWKT = nullptr;
1334 2980 : poSRS->exportToWkt(&pszWKT);
1335 2980 : if (!pszWKT)
1336 : {
1337 0 : return "";
1338 : }
1339 :
1340 : // If called on a thread-safe dataset, we might be called by several
1341 : // threads, so make sure our accesses to m_pszWKTCached are protected
1342 : // by a mutex.
1343 5960 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1344 2980 : if (m_poPrivate->m_pszWKTCached &&
1345 793 : strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1346 : {
1347 792 : CPLFree(pszWKT);
1348 792 : return m_poPrivate->m_pszWKTCached;
1349 : }
1350 2188 : CPLFree(m_poPrivate->m_pszWKTCached);
1351 2188 : m_poPrivate->m_pszWKTCached = pszWKT;
1352 2188 : return m_poPrivate->m_pszWKTCached;
1353 : }
1354 :
1355 : /************************************************************************/
1356 : /* GetSpatialRef() */
1357 : /************************************************************************/
1358 :
1359 : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1360 :
1361 : /**
1362 : * \brief Fetch the spatial reference for this dataset.
1363 : *
1364 : * Same as the C function GDALGetSpatialRef().
1365 : *
1366 : * When a projection definition is not available, null is returned. If used on
1367 : * a dataset where there are GCPs and not a geotransform, this method returns
1368 : * null. Use GetGCPSpatialRef() instead.
1369 : *
1370 : * Since GDAL 3.12, the default implementation of this method will iterate over
1371 : * vector layers and return their SRS if all geometry columns of all layers use
1372 : * the same SRS, or nullptr otherwise.
1373 : *
1374 : * @since GDAL 3.0
1375 : *
1376 : * @return a pointer to an internal object. It should not be altered or freed.
1377 : * Its lifetime will be the one of the dataset object.
1378 : *
1379 : * @see https://gdal.org/tutorials/osr_api_tut.html
1380 : */
1381 :
1382 17603 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1383 : {
1384 17603 : if (tlsEnableLayersInGetSpatialRefCounter == 0)
1385 17553 : return GetSpatialRefVectorOnly();
1386 50 : return nullptr;
1387 : }
1388 :
1389 : /************************************************************************/
1390 : /* GetSpatialRefVectorOnly() */
1391 : /************************************************************************/
1392 :
1393 : /**
1394 : * \brief Fetch the spatial reference for this dataset (only for vector layers)
1395 : *
1396 : * The default implementation of this method will iterate over
1397 : * vector layers and return their SRS if all geometry columns of all layers use
1398 : * the same SRS, or nullptr otherwise.
1399 : *
1400 : * @since GDAL 3.12
1401 : *
1402 : * @return a pointer to an internal object. It should not be altered or freed.
1403 : * Its lifetime will be the one of the dataset object.
1404 : */
1405 :
1406 17553 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1407 : {
1408 17553 : bool bInit = false;
1409 17553 : const OGRSpatialReference *poGlobalSRS = nullptr;
1410 33716 : for (const OGRLayer *poLayer : GetLayers())
1411 : {
1412 16164 : for (const auto *poGeomFieldDefn :
1413 48494 : poLayer->GetLayerDefn()->GetGeomFields())
1414 : {
1415 16167 : const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1416 16167 : if (!bInit)
1417 : {
1418 207 : bInit = true;
1419 207 : poGlobalSRS = poSRS;
1420 : }
1421 31918 : else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1422 15958 : (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1423 : {
1424 3 : CPLDebug("GDAL",
1425 : "Not all geometry fields or layers have the same CRS");
1426 3 : return nullptr;
1427 : }
1428 : }
1429 : }
1430 17550 : return poGlobalSRS;
1431 : }
1432 :
1433 : /************************************************************************/
1434 : /* GetSpatialRefRasterOnly() */
1435 : /************************************************************************/
1436 :
1437 : /**
1438 : * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
1439 : *
1440 : * @since GDAL 3.12
1441 : *
1442 : * @return a pointer to an internal object. It should not be altered or freed.
1443 : * Its lifetime will be the one of the dataset object.
1444 : */
1445 :
1446 901 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1447 : {
1448 901 : ++tlsEnableLayersInGetSpatialRefCounter;
1449 901 : const auto poRet = GetSpatialRef();
1450 901 : --tlsEnableLayersInGetSpatialRefCounter;
1451 901 : return poRet;
1452 : }
1453 :
1454 : /************************************************************************/
1455 : /* GDALGetSpatialRef() */
1456 : /************************************************************************/
1457 :
1458 : /**
1459 : * \brief Fetch the spatial reference for this dataset.
1460 : *
1461 : * Same as the C++ method GDALDataset::GetSpatialRef()
1462 : *
1463 : * @since GDAL 3.0
1464 : *
1465 : * @see GDALDataset::GetSpatialRef()
1466 : */
1467 :
1468 7135 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1469 :
1470 : {
1471 7135 : VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1472 :
1473 7135 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1474 7135 : GDALDataset::FromHandle(hDS)->GetSpatialRef()));
1475 : }
1476 :
1477 : /************************************************************************/
1478 : /* GDALGetProjectionRef() */
1479 : /************************************************************************/
1480 :
1481 : /**
1482 : * \brief Fetch the projection definition string for this dataset.
1483 : *
1484 : * @see GDALDataset::GetProjectionRef()
1485 : */
1486 :
1487 1501 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1488 :
1489 : {
1490 1501 : VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1491 :
1492 1501 : return GDALDataset::FromHandle(hDS)->GetProjectionRef();
1493 : }
1494 :
1495 : /************************************************************************/
1496 : /* SetProjection() */
1497 : /************************************************************************/
1498 :
1499 : /**
1500 : * \brief Set the projection reference string for this dataset.
1501 : *
1502 : * The string should be in OGC WKT or PROJ.4 format. An error may occur
1503 : * because of incorrectly specified projection strings, because the dataset
1504 : * is not writable, or because the dataset does not support the indicated
1505 : * projection. Many formats do not support writing projections.
1506 : *
1507 : * This method is the same as the C GDALSetProjection() function.
1508 : *
1509 : * \note Startig with GDAL 3.0, this is a compatibility layer around
1510 : * SetSpatialRef()
1511 :
1512 : * @param pszProjection projection reference string.
1513 : *
1514 : * @return CE_Failure if an error occurs, otherwise CE_None.
1515 : */
1516 :
1517 2482 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
1518 : {
1519 2482 : if (pszProjection && pszProjection[0] != '\0')
1520 : {
1521 4598 : OGRSpatialReference oSRS;
1522 2299 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1523 2299 : if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1524 : {
1525 2 : return CE_Failure;
1526 : }
1527 2297 : return SetSpatialRef(&oSRS);
1528 : }
1529 : else
1530 : {
1531 183 : return SetSpatialRef(nullptr);
1532 : }
1533 : }
1534 :
1535 : /************************************************************************/
1536 : /* SetSpatialRef() */
1537 : /************************************************************************/
1538 :
1539 : /**
1540 : * \brief Set the spatial reference system for this dataset.
1541 : *
1542 : * An error may occur because the dataset
1543 : * is not writable, or because the dataset does not support the indicated
1544 : * projection. Many formats do not support writing projections.
1545 : *
1546 : * This method is the same as the C GDALSetSpatialRef() function.
1547 : *
1548 : * @since GDAL 3.0
1549 :
1550 : * @param poSRS spatial reference system object. nullptr can potentially be
1551 : * passed for drivers that support unsetting the SRS.
1552 : *
1553 : * @return CE_Failure if an error occurs, otherwise CE_None.
1554 : */
1555 :
1556 0 : CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1557 : {
1558 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1559 0 : ReportError(CE_Failure, CPLE_NotSupported,
1560 : "Dataset does not support the SetSpatialRef() method.");
1561 0 : return CE_Failure;
1562 : }
1563 :
1564 : /************************************************************************/
1565 : /* GDALSetSpatialRef() */
1566 : /************************************************************************/
1567 :
1568 : /**
1569 : * \brief Set the spatial reference system for this dataset.
1570 : *
1571 : * @since GDAL 3.0
1572 : *
1573 : * @see GDALDataset::SetSpatialRef()
1574 : */
1575 :
1576 1301 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1577 :
1578 : {
1579 1301 : VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1580 :
1581 2602 : return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1582 1301 : OGRSpatialReference::FromHandle(hSRS));
1583 : }
1584 :
1585 : /************************************************************************/
1586 : /* GDALSetProjection() */
1587 : /************************************************************************/
1588 :
1589 : /**
1590 : * \brief Set the projection reference string for this dataset.
1591 : *
1592 : * @see GDALDataset::SetProjection()
1593 : */
1594 :
1595 1849 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1596 : const char *pszProjection)
1597 :
1598 : {
1599 1849 : VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1600 :
1601 1849 : return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
1602 : }
1603 :
1604 : /************************************************************************/
1605 : /* GetGeoTransform() */
1606 : /************************************************************************/
1607 :
1608 : /**
1609 : * \brief Fetch the affine transformation coefficients.
1610 : *
1611 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1612 : * space, and projection coordinates (Xp,Yp) space.
1613 : *
1614 : * \code
1615 : * Xp = gt[0] + P*gt[1] + L*gt[2];
1616 : * Yp = gt[3] + P*padfTransform[4] + L*gt[5];
1617 : * \endcode
1618 : *
1619 : * In a north up image, gt[1] is the pixel width, and
1620 : * gt[5] is the pixel height. The upper left corner of the
1621 : * upper left pixel is at position (gt[0],gt[3]).
1622 : *
1623 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1624 : * a CE_Failure error is returned, such as for formats that don't support
1625 : * transformation to projection coordinates.
1626 : *
1627 : * This method does the same thing as the C GDALGetGeoTransform() function.
1628 : *
1629 : * @param gt an existing six double buffer into which the
1630 : * transformation will be placed.
1631 : *
1632 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1633 : *
1634 : * @since 3.12
1635 : */
1636 :
1637 16004 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform >) const
1638 :
1639 : {
1640 16004 : gt = GDALGeoTransform();
1641 :
1642 16004 : return CE_Failure;
1643 : }
1644 :
1645 : /************************************************************************/
1646 : /* GetGeoTransform() */
1647 : /************************************************************************/
1648 :
1649 : /**
1650 : * \brief Fetch the affine transformation coefficients.
1651 : *
1652 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1653 : * space, and projection coordinates (Xp,Yp) space.
1654 : *
1655 : * \code
1656 : * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
1657 : * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
1658 : * \endcode
1659 : *
1660 : * In a north up image, padfTransform[1] is the pixel width, and
1661 : * padfTransform[5] is the pixel height. The upper left corner of the
1662 : * upper left pixel is at position (padfTransform[0],padfTransform[3]).
1663 : *
1664 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1665 : * a CE_Failure error is returned, such as for formats that don't support
1666 : * transformation to projection coordinates.
1667 : *
1668 : * This method does the same thing as the C GDALGetGeoTransform() function.
1669 : *
1670 : * @param padfTransform an existing six double buffer into which the
1671 : * transformation will be placed.
1672 : *
1673 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1674 : *
1675 : * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
1676 : */
1677 :
1678 2 : CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
1679 :
1680 : {
1681 2 : return GetGeoTransform(
1682 2 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1683 : }
1684 :
1685 : /************************************************************************/
1686 : /* GDALGetGeoTransform() */
1687 : /************************************************************************/
1688 :
1689 : /**
1690 : * \brief Fetch the affine transformation coefficients.
1691 : *
1692 : * @see GDALDataset::GetGeoTransform()
1693 : */
1694 :
1695 9291 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1696 :
1697 : {
1698 9291 : VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1699 :
1700 18582 : return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1701 9291 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1702 : }
1703 :
1704 : /************************************************************************/
1705 : /* SetGeoTransform() */
1706 : /************************************************************************/
1707 :
1708 : /**
1709 : * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
1710 : * \brief Set the affine transformation coefficients.
1711 : *
1712 : * See GetGeoTransform() for details on the meaning of the padfTransform
1713 : * coefficients.
1714 : *
1715 : * This method does the same thing as the C GDALSetGeoTransform() function.
1716 : *
1717 : * @param gt the transformation coefficients to be written with the dataset.
1718 : *
1719 : * @return CE_None on success, or CE_Failure if this transform cannot be
1720 : * written.
1721 : *
1722 : * @since 3.12
1723 : */
1724 :
1725 0 : CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform >)
1726 :
1727 : {
1728 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1729 0 : ReportError(CE_Failure, CPLE_NotSupported,
1730 : "SetGeoTransform() not supported for this dataset.");
1731 :
1732 0 : return CE_Failure;
1733 : }
1734 :
1735 : /************************************************************************/
1736 : /* SetGeoTransform() */
1737 : /************************************************************************/
1738 :
1739 : /**
1740 : * \brief Set the affine transformation coefficients.
1741 : *
1742 : * See GetGeoTransform() for details on the meaning of the padfTransform
1743 : * coefficients.
1744 : *
1745 : * This method does the same thing as the C GDALSetGeoTransform() function.
1746 : *
1747 : * @param padfTransform a six double buffer containing the transformation
1748 : * coefficients to be written with the dataset.
1749 : *
1750 : * @return CE_None on success, or CE_Failure if this transform cannot be
1751 : * written.
1752 : *
1753 : * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
1754 : */
1755 30 : CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
1756 :
1757 : {
1758 30 : return SetGeoTransform(
1759 30 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1760 : }
1761 :
1762 : /************************************************************************/
1763 : /* GDALSetGeoTransform() */
1764 : /************************************************************************/
1765 :
1766 : /**
1767 : * \brief Set the affine transformation coefficients.
1768 : *
1769 : * @see GDALDataset::SetGeoTransform()
1770 : */
1771 :
1772 4319 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1773 : const double *padfTransform)
1774 :
1775 : {
1776 4319 : VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1777 4319 : VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1778 :
1779 8638 : return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1780 4319 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1781 : }
1782 :
1783 : /************************************************************************/
1784 : /* GetInternalHandle() */
1785 : /************************************************************************/
1786 :
1787 : /**
1788 : * \fn GDALDataset::GetInternalHandle(const char*)
1789 : * \brief Fetch a format specific internally meaningful handle.
1790 : *
1791 : * This method is the same as the C GDALGetInternalHandle() method.
1792 : *
1793 : * @param pszHandleName the handle name desired. The meaningful names
1794 : * will be specific to the file format.
1795 : *
1796 : * @return the desired handle value, or NULL if not recognized/supported.
1797 : */
1798 :
1799 194 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1800 :
1801 : {
1802 194 : return nullptr;
1803 : }
1804 :
1805 : /************************************************************************/
1806 : /* GDALGetInternalHandle() */
1807 : /************************************************************************/
1808 :
1809 : /**
1810 : * \brief Fetch a format specific internally meaningful handle.
1811 : *
1812 : * @see GDALDataset::GetInternalHandle()
1813 : */
1814 :
1815 61 : void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1816 : const char *pszRequest)
1817 :
1818 : {
1819 61 : VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1820 :
1821 61 : return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
1822 : }
1823 :
1824 : /************************************************************************/
1825 : /* GetDriver() */
1826 : /************************************************************************/
1827 :
1828 : /**
1829 : * \brief Fetch the driver to which this dataset relates.
1830 : *
1831 : * This method is the same as the C GDALGetDatasetDriver() function.
1832 : *
1833 : * @return the driver on which the dataset was created with GDALOpen() or
1834 : * GDALCreate().
1835 : */
1836 :
1837 32422 : GDALDriver *GDALDataset::GetDriver()
1838 : {
1839 32422 : return poDriver;
1840 : }
1841 :
1842 : /************************************************************************/
1843 : /* GDALGetDatasetDriver() */
1844 : /************************************************************************/
1845 :
1846 : /**
1847 : * \brief Fetch the driver to which this dataset relates.
1848 : *
1849 : * @see GDALDataset::GetDriver()
1850 : */
1851 :
1852 2706 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1853 :
1854 : {
1855 2706 : VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1856 :
1857 : return static_cast<GDALDriverH>(
1858 2706 : GDALDataset::FromHandle(hDataset)->GetDriver());
1859 : }
1860 :
1861 : /************************************************************************/
1862 : /* Reference() */
1863 : /************************************************************************/
1864 :
1865 : /**
1866 : * \brief Add one to dataset reference count.
1867 : *
1868 : * The reference is one after instantiation.
1869 : *
1870 : * This method is the same as the C GDALReferenceDataset() function.
1871 : *
1872 : * @return the post-increment reference count.
1873 : */
1874 :
1875 259334 : int GDALDataset::Reference()
1876 : {
1877 259334 : return ++nRefCount;
1878 : }
1879 :
1880 : /************************************************************************/
1881 : /* GDALReferenceDataset() */
1882 : /************************************************************************/
1883 :
1884 : /**
1885 : * \brief Add one to dataset reference count.
1886 : *
1887 : * @see GDALDataset::Reference()
1888 : */
1889 :
1890 1300 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1891 :
1892 : {
1893 1300 : VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1894 :
1895 1300 : return GDALDataset::FromHandle(hDataset)->Reference();
1896 : }
1897 :
1898 : /************************************************************************/
1899 : /* Dereference() */
1900 : /************************************************************************/
1901 :
1902 : /**
1903 : * \brief Subtract one from dataset reference count.
1904 : *
1905 : * The reference is one after instantiation. Generally when the reference
1906 : * count has dropped to zero the dataset may be safely deleted (closed).
1907 : *
1908 : * This method is the same as the C GDALDereferenceDataset() function.
1909 : *
1910 : * @return the post-decrement reference count.
1911 : */
1912 :
1913 319948 : int GDALDataset::Dereference()
1914 : {
1915 319948 : return --nRefCount;
1916 : }
1917 :
1918 : /************************************************************************/
1919 : /* GDALDereferenceDataset() */
1920 : /************************************************************************/
1921 :
1922 : /**
1923 : * \brief Subtract one from dataset reference count.
1924 : *
1925 : * @see GDALDataset::Dereference()
1926 : */
1927 :
1928 58861 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1929 :
1930 : {
1931 58861 : VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1932 :
1933 58861 : return GDALDataset::FromHandle(hDataset)->Dereference();
1934 : }
1935 :
1936 : /************************************************************************/
1937 : /* ReleaseRef() */
1938 : /************************************************************************/
1939 :
1940 : /**
1941 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1942 : * @return TRUE if the object has been destroyed.
1943 : */
1944 :
1945 251798 : int GDALDataset::ReleaseRef()
1946 :
1947 : {
1948 251798 : if (Dereference() <= 0)
1949 : {
1950 7445 : nRefCount = 1;
1951 7445 : delete this;
1952 7445 : return TRUE;
1953 : }
1954 244353 : return FALSE;
1955 : }
1956 :
1957 : /************************************************************************/
1958 : /* GDALReleaseDataset() */
1959 : /************************************************************************/
1960 :
1961 : /**
1962 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1963 : *
1964 : * @see GDALDataset::ReleaseRef()
1965 : */
1966 :
1967 1537 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1968 :
1969 : {
1970 1537 : VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1971 :
1972 1537 : return GDALDataset::FromHandle(hDataset)->ReleaseRef();
1973 : }
1974 :
1975 : /************************************************************************/
1976 : /* GetShared() */
1977 : /************************************************************************/
1978 :
1979 : /**
1980 : * \brief Returns shared flag.
1981 : *
1982 : * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
1983 : */
1984 :
1985 309873 : int GDALDataset::GetShared() const
1986 : {
1987 309873 : return bShared;
1988 : }
1989 :
1990 : /************************************************************************/
1991 : /* MarkAsShared() */
1992 : /************************************************************************/
1993 :
1994 : /**
1995 : * \brief Mark this dataset as available for sharing.
1996 : */
1997 :
1998 435 : void GDALDataset::MarkAsShared()
1999 :
2000 : {
2001 435 : CPLAssert(!bShared);
2002 :
2003 435 : bShared = true;
2004 435 : if (bIsInternal)
2005 23 : return;
2006 :
2007 412 : GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
2008 :
2009 : // Insert the dataset in the set of shared opened datasets.
2010 824 : CPLMutexHolderD(&hDLMutex);
2011 412 : if (phSharedDatasetSet == nullptr)
2012 276 : phSharedDatasetSet =
2013 276 : CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2014 : GDALSharedDatasetFreeFunc);
2015 :
2016 : SharedDatasetCtxt *psStruct =
2017 412 : static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2018 412 : psStruct->poDS = this;
2019 412 : psStruct->nPID = nPID;
2020 412 : psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2021 412 : psStruct->pszDescription = CPLStrdup(GetDescription());
2022 : std::string osConcatenatedOpenOptions =
2023 824 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2024 412 : psStruct->pszConcatenatedOpenOptions =
2025 412 : CPLStrdup(osConcatenatedOpenOptions.c_str());
2026 412 : if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
2027 : {
2028 1 : GDALSharedDatasetFreeFunc(psStruct);
2029 1 : ReportError(CE_Failure, CPLE_AppDefined,
2030 : "An existing shared dataset already has this description. "
2031 : "This should not happen.");
2032 : }
2033 : else
2034 : {
2035 411 : CPLHashSetInsert(phSharedDatasetSet, psStruct);
2036 :
2037 411 : (*poAllDatasetMap)[this] = nPID;
2038 : }
2039 : }
2040 :
2041 : /************************************************************************/
2042 : /* MarkSuppressOnClose() */
2043 : /************************************************************************/
2044 :
2045 : /** Set that the dataset must be deleted on close.
2046 : *
2047 : * This is the same as C function GDALDatasetMarkSuppressOnClose()
2048 : */
2049 1230 : void GDALDataset::MarkSuppressOnClose()
2050 : {
2051 1230 : bSuppressOnClose = true;
2052 1230 : }
2053 :
2054 : /************************************************************************/
2055 : /* GDALDatasetMarkSuppressOnClose() */
2056 : /************************************************************************/
2057 :
2058 : /** Set that the dataset must be deleted on close.
2059 : *
2060 : * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2061 : *
2062 : * @since GDAL 3.12
2063 : */
2064 :
2065 4 : void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2066 : {
2067 4 : VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2068 :
2069 4 : return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2070 : }
2071 :
2072 : /************************************************************************/
2073 : /* UnMarkSuppressOnClose() */
2074 : /************************************************************************/
2075 :
2076 : /** Remove the flag requesting the dataset to be deleted on close. */
2077 684 : void GDALDataset::UnMarkSuppressOnClose()
2078 : {
2079 684 : bSuppressOnClose = false;
2080 684 : }
2081 :
2082 : /************************************************************************/
2083 : /* CleanupPostFileClosing() */
2084 : /************************************************************************/
2085 :
2086 : /** This method should be called by driver implementations in their destructor,
2087 : * after having closed all files, but before having freed resources that
2088 : * are needed for their GetFileList() implementation.
2089 : * This is used to implement MarkSuppressOnClose behavior.
2090 : */
2091 259 : void GDALDataset::CleanupPostFileClosing()
2092 : {
2093 259 : if (IsMarkedSuppressOnClose())
2094 : {
2095 1 : char **papszFileList = GetFileList();
2096 3 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
2097 2 : VSIUnlink(papszFileList[i]);
2098 1 : CSLDestroy(papszFileList);
2099 : }
2100 259 : }
2101 :
2102 : /************************************************************************/
2103 : /* GetGCPCount() */
2104 : /************************************************************************/
2105 :
2106 : /**
2107 : * \brief Get number of GCPs.
2108 : *
2109 : * This method is the same as the C function GDALGetGCPCount().
2110 : *
2111 : * @return number of GCPs for this dataset. Zero if there are none.
2112 : */
2113 :
2114 16546 : int GDALDataset::GetGCPCount()
2115 : {
2116 16546 : return 0;
2117 : }
2118 :
2119 : /************************************************************************/
2120 : /* GDALGetGCPCount() */
2121 : /************************************************************************/
2122 :
2123 : /**
2124 : * \brief Get number of GCPs.
2125 : *
2126 : * @see GDALDataset::GetGCPCount()
2127 : */
2128 :
2129 2160 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2130 :
2131 : {
2132 2160 : VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2133 :
2134 2160 : return GDALDataset::FromHandle(hDS)->GetGCPCount();
2135 : }
2136 :
2137 : /************************************************************************/
2138 : /* GetGCPProjection() */
2139 : /************************************************************************/
2140 :
2141 : /**
2142 : * \brief Get output projection for GCPs.
2143 : *
2144 : * This method is the same as the C function GDALGetGCPProjection().
2145 : *
2146 : * The projection string follows the normal rules from GetProjectionRef().
2147 : *
2148 : * \note Starting with GDAL 3.0, this is a compatibility layer around
2149 : * GetGCPSpatialRef()
2150 : *
2151 : * @return internal projection string or "" if there are no GCPs.
2152 : * It should not be altered, freed or expected to last for long.
2153 : */
2154 :
2155 930 : const char *GDALDataset::GetGCPProjection() const
2156 : {
2157 930 : const auto poSRS = GetGCPSpatialRef();
2158 930 : if (!poSRS || !m_poPrivate)
2159 : {
2160 594 : return "";
2161 : }
2162 336 : char *pszWKT = nullptr;
2163 336 : poSRS->exportToWkt(&pszWKT);
2164 336 : if (!pszWKT)
2165 : {
2166 0 : return "";
2167 : }
2168 :
2169 : // If called on a thread-safe dataset, we might be called by several
2170 : // threads, so make sure our accesses to m_pszWKTCached are protected
2171 : // by a mutex.
2172 672 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2173 336 : if (m_poPrivate->m_pszWKTGCPCached &&
2174 256 : strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2175 : {
2176 256 : CPLFree(pszWKT);
2177 256 : return m_poPrivate->m_pszWKTGCPCached;
2178 : }
2179 80 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
2180 80 : m_poPrivate->m_pszWKTGCPCached = pszWKT;
2181 80 : return m_poPrivate->m_pszWKTGCPCached;
2182 : }
2183 :
2184 : /************************************************************************/
2185 : /* GetGCPSpatialRef() */
2186 : /************************************************************************/
2187 :
2188 : /**
2189 : * \brief Get output spatial reference system for GCPs.
2190 : *
2191 : * Same as the C function GDALGetGCPSpatialRef().
2192 : *
2193 : * When a SRS is not available, null is returned. If used on
2194 : * a dataset where there is a geotransform, and not GCPs, this method returns
2195 : * null. Use GetSpatialRef() instead.
2196 : *
2197 : * @since GDAL 3.0
2198 : *
2199 : * @return a pointer to an internal object. It should not be altered or freed.
2200 : * Its lifetime will be the one of the dataset object, or until the next
2201 : * call to this method.
2202 : */
2203 :
2204 39 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2205 : {
2206 39 : return nullptr;
2207 : }
2208 :
2209 : /************************************************************************/
2210 : /* GDALGetGCPSpatialRef() */
2211 : /************************************************************************/
2212 :
2213 : /**
2214 : * \brief Get output spatial reference system for GCPs.
2215 : *
2216 : * @since GDAL 3.0
2217 : *
2218 : * @see GDALDataset::GetGCPSpatialRef()
2219 : */
2220 :
2221 468 : OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2222 :
2223 : {
2224 468 : VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2225 :
2226 468 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2227 468 : GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2228 : }
2229 :
2230 : /************************************************************************/
2231 : /* GDALGetGCPProjection() */
2232 : /************************************************************************/
2233 :
2234 : /**
2235 : * \brief Get output projection for GCPs.
2236 : *
2237 : * @see GDALDataset::GetGCPProjection()
2238 : */
2239 :
2240 860 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2241 :
2242 : {
2243 860 : VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2244 :
2245 860 : return GDALDataset::FromHandle(hDS)->GetGCPProjection();
2246 : }
2247 :
2248 : /************************************************************************/
2249 : /* GetGCPs() */
2250 : /************************************************************************/
2251 :
2252 : /**
2253 : * \brief Fetch GCPs.
2254 : *
2255 : * This method is the same as the C function GDALGetGCPs().
2256 : *
2257 : * @return pointer to internal GCP structure list. It should not be modified,
2258 : * and may change on the next GDAL call.
2259 : */
2260 :
2261 11 : const GDAL_GCP *GDALDataset::GetGCPs()
2262 : {
2263 11 : return nullptr;
2264 : }
2265 :
2266 : /************************************************************************/
2267 : /* GDALGetGCPs() */
2268 : /************************************************************************/
2269 :
2270 : /**
2271 : * \brief Fetch GCPs.
2272 : *
2273 : * @see GDALDataset::GetGCPs()
2274 : */
2275 :
2276 579 : const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2277 :
2278 : {
2279 579 : VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2280 :
2281 579 : return GDALDataset::FromHandle(hDS)->GetGCPs();
2282 : }
2283 :
2284 : /************************************************************************/
2285 : /* SetGCPs() */
2286 : /************************************************************************/
2287 :
2288 : /**
2289 : * \brief Assign GCPs.
2290 : *
2291 : * This method is the same as the C function GDALSetGCPs().
2292 : *
2293 : * This method assigns the passed set of GCPs to this dataset, as well as
2294 : * setting their coordinate system. Internally copies are made of the
2295 : * coordinate system and list of points, so the caller remains responsible for
2296 : * deallocating these arguments if appropriate.
2297 : *
2298 : * Most formats do not support setting of GCPs, even formats that can
2299 : * handle GCPs. These formats will return CE_Failure.
2300 : *
2301 : * \note Startig with GDAL 3.0, this is a compatibility layer around
2302 : * SetGCPs(int, const GDAL_GCP*, const char*)
2303 : *
2304 : * @param nGCPCount number of GCPs being assigned.
2305 : *
2306 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2307 : *
2308 : * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
2309 : * GCP output coordinates. This parameter should be "" if no output coordinate
2310 : * system is known.
2311 : *
2312 : * @return CE_None on success, CE_Failure on failure (including if action is
2313 : * not supported for this format).
2314 : */
2315 :
2316 52 : CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2317 : const char *pszGCPProjection)
2318 :
2319 : {
2320 52 : if (pszGCPProjection && pszGCPProjection[0] != '\0')
2321 : {
2322 66 : OGRSpatialReference oSRS;
2323 33 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2324 33 : if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
2325 : {
2326 0 : return CE_Failure;
2327 : }
2328 33 : return SetGCPs(nGCPCount, pasGCPList, &oSRS);
2329 : }
2330 : else
2331 : {
2332 19 : return SetGCPs(nGCPCount, pasGCPList,
2333 19 : static_cast<const OGRSpatialReference *>(nullptr));
2334 : }
2335 : }
2336 :
2337 : /************************************************************************/
2338 : /* SetGCPs() */
2339 : /************************************************************************/
2340 :
2341 : /**
2342 : * \brief Assign GCPs.
2343 : *
2344 : * This method is the same as the C function GDALSetGCPs().
2345 : *
2346 : * This method assigns the passed set of GCPs to this dataset, as well as
2347 : * setting their coordinate system. Internally copies are made of the
2348 : * coordinate system and list of points, so the caller remains responsible for
2349 : * deallocating these arguments if appropriate.
2350 : *
2351 : * Most formats do not support setting of GCPs, even formats that can
2352 : * handle GCPs. These formats will return CE_Failure.
2353 : *
2354 : * @since GDAL 3.0
2355 : *
2356 : * @param nGCPCount number of GCPs being assigned.
2357 : *
2358 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2359 : *
2360 : * @param poGCP_SRS the new coordinate reference system to assign for the
2361 : * GCP output coordinates. This parameter should be null if no output
2362 : * coordinate system is known.
2363 : *
2364 : * @return CE_None on success, CE_Failure on failure (including if action is
2365 : * not supported for this format).
2366 : */
2367 :
2368 1 : CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
2369 : CPL_UNUSED const GDAL_GCP *pasGCPList,
2370 : CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
2371 :
2372 : {
2373 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2374 1 : ReportError(CE_Failure, CPLE_NotSupported,
2375 : "Dataset does not support the SetGCPs() method.");
2376 :
2377 1 : return CE_Failure;
2378 : }
2379 :
2380 : /************************************************************************/
2381 : /* GDALSetGCPs() */
2382 : /************************************************************************/
2383 :
2384 : /**
2385 : * \brief Assign GCPs.
2386 : *
2387 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
2388 : */
2389 :
2390 29 : CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2391 : const GDAL_GCP *pasGCPList,
2392 : const char *pszGCPProjection)
2393 :
2394 : {
2395 29 : VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2396 :
2397 29 : return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2398 29 : pszGCPProjection);
2399 : }
2400 :
2401 : /************************************************************************/
2402 : /* GDALSetGCPs2() */
2403 : /************************************************************************/
2404 :
2405 : /**
2406 : * \brief Assign GCPs.
2407 : *
2408 : * @since GDAL 3.0
2409 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
2410 : */
2411 :
2412 9 : CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
2413 : OGRSpatialReferenceH hSRS)
2414 :
2415 : {
2416 9 : VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
2417 :
2418 18 : return GDALDataset::FromHandle(hDS)->SetGCPs(
2419 9 : nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
2420 : }
2421 :
2422 : /************************************************************************/
2423 : /* BuildOverviews() */
2424 : /************************************************************************/
2425 :
2426 : /**
2427 : * \brief Build raster overview(s)
2428 : *
2429 : * If the operation is not supported for the indicated dataset, then
2430 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2431 : * CPLE_NotSupported.
2432 : *
2433 : * Depending on the actual file format, all overviews level can be also
2434 : * deleted by specifying nOverviews == 0. This works at least for external
2435 : * overviews (.ovr), TIFF internal overviews, etc.
2436 : *
2437 : * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
2438 : * to "ALL_CPUS" or a integer value to specify the number of threads to use for
2439 : * overview computation.
2440 : *
2441 : * This method is the same as the C function GDALBuildOverviewsEx().
2442 : *
2443 : * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
2444 : * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
2445 : * or "NONE" controlling the downsampling method applied.
2446 : * @param nOverviews number of overviews to build, or 0 to clean overviews.
2447 : * @param panOverviewList the list of overview decimation factors (positive
2448 : * integers, normally larger or equal to 2) to build, or
2449 : * NULL if nOverviews == 0.
2450 : * @param nListBands number of bands to build overviews for in panBandList.
2451 : * Build for all bands if this is 0.
2452 : * @param panBandList list of band numbers.
2453 : * @param pfnProgress a function to call to report progress, or NULL.
2454 : * @param pProgressData application data to pass to the progress function.
2455 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2456 : * key=value pairs, or NULL.
2457 : * Possible keys are the ones returned by
2458 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2459 : *
2460 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2461 : *
2462 : * For example, to build overview level 2, 4 and 8 on all bands the following
2463 : * call could be made:
2464 : * \code{.cpp}
2465 : * int anOverviewList[3] = { 2, 4, 8 };
2466 : *
2467 : * poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
2468 : * GDALDummyProgress, nullptr );
2469 : * \endcode
2470 : *
2471 : * @see GDALRegenerateOverviewsEx()
2472 : */
2473 :
2474 748 : CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
2475 : const int *panOverviewList, int nListBands,
2476 : const int *panBandList,
2477 : GDALProgressFunc pfnProgress,
2478 : void *pProgressData,
2479 : CSLConstList papszOptions)
2480 : {
2481 748 : int *panAllBandList = nullptr;
2482 :
2483 1496 : CPLStringList aosOptions(papszOptions);
2484 748 : if (poDriver && !aosOptions.empty())
2485 : {
2486 : const char *pszOptionList =
2487 28 : poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
2488 28 : if (pszOptionList)
2489 : {
2490 : // For backwards compatibility
2491 28 : if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
2492 : {
2493 4 : if (strstr(pszOptionList, "<Value>RRD</Value>") &&
2494 2 : aosOptions.FetchNameValue("LOCATION") == nullptr)
2495 : {
2496 2 : if (CPLTestBool(opt))
2497 2 : aosOptions.SetNameValue("LOCATION", "RRD");
2498 2 : aosOptions.SetNameValue("USE_RRD", nullptr);
2499 : }
2500 : }
2501 28 : if (const char *opt =
2502 28 : aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
2503 : {
2504 3 : if (strstr(pszOptionList, "VIRTUAL"))
2505 : {
2506 3 : aosOptions.SetNameValue("VIRTUAL", opt);
2507 3 : aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
2508 : }
2509 : }
2510 :
2511 76 : for (const auto &[pszKey, pszValue] :
2512 104 : cpl::IterateNameValue(papszOptions))
2513 : {
2514 38 : if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
2515 : {
2516 : aosOptions.SetNameValue(
2517 16 : std::string(pszKey)
2518 16 : .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
2519 : .c_str(),
2520 16 : pszValue);
2521 8 : aosOptions.SetNameValue(pszKey, nullptr);
2522 : }
2523 : }
2524 :
2525 56 : CPLString osDriver;
2526 28 : osDriver.Printf("driver %s", poDriver->GetDescription());
2527 28 : GDALValidateOptions(pszOptionList, aosOptions.List(),
2528 : "overview creation option", osDriver);
2529 : }
2530 : }
2531 :
2532 748 : if (nListBands == 0)
2533 : {
2534 736 : nListBands = GetRasterCount();
2535 : panAllBandList =
2536 736 : static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2537 67468 : for (int i = 0; i < nListBands; ++i)
2538 66732 : panAllBandList[i] = i + 1;
2539 :
2540 736 : panBandList = panAllBandList;
2541 : }
2542 :
2543 748 : if (pfnProgress == nullptr)
2544 713 : pfnProgress = GDALDummyProgress;
2545 :
2546 1828 : for (int i = 0; i < nOverviews; ++i)
2547 : {
2548 1081 : if (panOverviewList[i] <= 0)
2549 : {
2550 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2551 : "panOverviewList[%d] = %d is invalid. It must be a "
2552 : "positive value",
2553 1 : i, panOverviewList[i]);
2554 1 : CPLFree(panAllBandList);
2555 1 : return CE_Failure;
2556 : }
2557 : }
2558 :
2559 747 : const CPLErr eErr = IBuildOverviews(
2560 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2561 747 : pfnProgress, pProgressData, aosOptions.List());
2562 :
2563 747 : if (panAllBandList != nullptr)
2564 734 : CPLFree(panAllBandList);
2565 :
2566 747 : return eErr;
2567 : }
2568 :
2569 : /************************************************************************/
2570 : /* GDALBuildOverviews() */
2571 : /************************************************************************/
2572 :
2573 : /**
2574 : * \brief Build raster overview(s)
2575 : *
2576 : * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2577 : */
2578 :
2579 27 : CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2580 : const char *pszResampling, int nOverviews,
2581 : const int *panOverviewList,
2582 : int nListBands, const int *panBandList,
2583 : GDALProgressFunc pfnProgress,
2584 : void *pProgressData)
2585 :
2586 : {
2587 27 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2588 :
2589 27 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2590 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2591 27 : pfnProgress, pProgressData, nullptr);
2592 : }
2593 :
2594 : /************************************************************************/
2595 : /* GDALBuildOverviews() */
2596 : /************************************************************************/
2597 :
2598 : /**
2599 : * \brief Build raster overview(s)
2600 : *
2601 : * @see GDALDataset::BuildOverviews()
2602 : * @since GDAL 3.6
2603 : */
2604 :
2605 : CPLErr CPL_STDCALL
2606 700 : GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2607 : int nOverviews, const int *panOverviewList, int nListBands,
2608 : const int *panBandList, GDALProgressFunc pfnProgress,
2609 : void *pProgressData, CSLConstList papszOptions)
2610 :
2611 : {
2612 700 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2613 :
2614 700 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2615 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2616 700 : pfnProgress, pProgressData, papszOptions);
2617 : }
2618 :
2619 : /************************************************************************/
2620 : /* IBuildOverviews() */
2621 : /* */
2622 : /* Default implementation. */
2623 : /************************************************************************/
2624 :
2625 : //! @cond Doxygen_Suppress
2626 196 : CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2627 : const int *panOverviewList, int nListBands,
2628 : const int *panBandList,
2629 : GDALProgressFunc pfnProgress,
2630 : void *pProgressData,
2631 : CSLConstList papszOptions)
2632 :
2633 : {
2634 196 : if (oOvManager.IsInitialized())
2635 195 : return oOvManager.BuildOverviews(
2636 : nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2637 195 : panBandList, pfnProgress, pProgressData, papszOptions);
2638 : else
2639 : {
2640 1 : ReportError(CE_Failure, CPLE_NotSupported,
2641 : "BuildOverviews() not supported for this dataset.");
2642 :
2643 1 : return CE_Failure;
2644 : }
2645 : }
2646 :
2647 : //! @endcond
2648 :
2649 : /************************************************************************/
2650 : /* AddOverviews() */
2651 : /* */
2652 : /* Default implementation. */
2653 : /************************************************************************/
2654 :
2655 : /**
2656 : * \brief Add overview from existing dataset(s)
2657 : *
2658 : * This function creates new overview levels or refresh existing one from
2659 : * the list of provided overview datasets.
2660 : * Source overviews may come from any GDAL supported format, provided they
2661 : * have the same number of bands and geospatial extent than the target
2662 : * dataset.
2663 : *
2664 : * If the operation is not supported for the indicated dataset, then
2665 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2666 : * CPLE_NotSupported.
2667 : *
2668 : * At time of writing, this method is only implemented for internal overviews
2669 : * of GeoTIFF datasets and external overviews in GeoTIFF format.
2670 : *
2671 : * @param apoSrcOvrDS Vector of source overviews.
2672 : * @param pfnProgress a function to call to report progress, or NULL.
2673 : * @param pProgressData application data to pass to the progress function.
2674 : * @param papszOptions NULL terminated list of options as
2675 : * key=value pairs, or NULL. Possible keys are the
2676 : * ones returned by
2677 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2678 : *
2679 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2680 : * @since 3.12
2681 : */
2682 5 : CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2683 : GDALProgressFunc pfnProgress,
2684 : void *pProgressData, CSLConstList papszOptions)
2685 : {
2686 5 : if (oOvManager.IsInitialized())
2687 : {
2688 4 : return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2689 4 : pProgressData, papszOptions);
2690 : }
2691 : else
2692 : {
2693 1 : ReportError(CE_Failure, CPLE_NotSupported,
2694 : "AddOverviews() not supported for this dataset.");
2695 1 : return CE_Failure;
2696 : }
2697 : }
2698 :
2699 : /************************************************************************/
2700 : /* IRasterIO() */
2701 : /* */
2702 : /* The default implementation of IRasterIO() is, in the general */
2703 : /* case to pass the request off to each band objects rasterio */
2704 : /* methods with appropriate arguments. In some cases, it might */
2705 : /* choose instead the BlockBasedRasterIO() implementation. */
2706 : /************************************************************************/
2707 :
2708 : //! @cond Doxygen_Suppress
2709 444828 : CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2710 : int nXSize, int nYSize, void *pData,
2711 : int nBufXSize, int nBufYSize,
2712 : GDALDataType eBufType, int nBandCount,
2713 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2714 : GSpacing nLineSpace, GSpacing nBandSpace,
2715 : GDALRasterIOExtraArg *psExtraArg)
2716 :
2717 : {
2718 444828 : const char *pszInterleave = nullptr;
2719 :
2720 444828 : CPLAssert(nullptr != pData);
2721 :
2722 444828 : const bool bHasSubpixelShift =
2723 447111 : psExtraArg->bFloatingPointWindowValidity &&
2724 445621 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2725 793 : (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2726 :
2727 444712 : if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2728 70527 : nBandCount > 1 &&
2729 70527 : (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2730 889540 : nullptr &&
2731 67447 : EQUAL(pszInterleave, "PIXEL"))
2732 : {
2733 64132 : return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2734 : nBufXSize, nBufYSize, eBufType, nBandCount,
2735 : panBandMap, nPixelSpace, nLineSpace,
2736 64132 : nBandSpace, psExtraArg);
2737 : }
2738 :
2739 380696 : if (eRWFlag == GF_Read &&
2740 201135 : (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2741 200347 : psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2742 200346 : psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2743 201135 : psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2744 951 : !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2745 : {
2746 930 : if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2747 : {
2748 719 : int bTried = FALSE;
2749 719 : const CPLErr eErr = TryOverviewRasterIO(
2750 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2751 : nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2752 : nLineSpace, nBandSpace, psExtraArg, &bTried);
2753 719 : if (bTried)
2754 1 : return eErr;
2755 : }
2756 :
2757 929 : GDALDataType eFirstBandDT = GDT_Unknown;
2758 929 : int nFirstMaskFlags = 0;
2759 929 : GDALRasterBand *poFirstMaskBand = nullptr;
2760 929 : int nOKBands = 0;
2761 :
2762 : // Check if bands share the same mask band
2763 2921 : for (int i = 0; i < nBandCount; ++i)
2764 : {
2765 2652 : GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2766 4629 : if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2767 1977 : poBand->GetOverviewCount())
2768 : {
2769 : // Could be improved to select the appropriate overview.
2770 3 : break;
2771 : }
2772 2649 : if (poBand->GetColorTable() != nullptr)
2773 : {
2774 0 : break;
2775 : }
2776 2649 : const GDALDataType eDT = poBand->GetRasterDataType();
2777 2649 : if (GDALDataTypeIsComplex(eDT))
2778 : {
2779 30 : break;
2780 : }
2781 2619 : if (i == 0)
2782 : {
2783 896 : eFirstBandDT = eDT;
2784 896 : nFirstMaskFlags = poBand->GetMaskFlags();
2785 896 : if (nFirstMaskFlags == GMF_NODATA)
2786 : {
2787 : // The dataset-level resampling code is not ready for nodata
2788 : // Fallback to band-level resampling
2789 10 : break;
2790 : }
2791 886 : poFirstMaskBand = poBand->GetMaskBand();
2792 : }
2793 : else
2794 : {
2795 1723 : if (eDT != eFirstBandDT)
2796 : {
2797 0 : break;
2798 : }
2799 1723 : int nMaskFlags = poBand->GetMaskFlags();
2800 1723 : if (nMaskFlags == GMF_NODATA)
2801 : {
2802 : // The dataset-level resampling code is not ready for nodata
2803 : // Fallback to band-level resampling
2804 0 : break;
2805 : }
2806 1723 : GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2807 1723 : if (nFirstMaskFlags == GMF_ALL_VALID &&
2808 : nMaskFlags == GMF_ALL_VALID)
2809 : {
2810 : // Ok.
2811 : }
2812 1077 : else if (poFirstMaskBand == poMaskBand)
2813 : {
2814 : // Ok.
2815 : }
2816 : else
2817 : {
2818 617 : break;
2819 : }
2820 : }
2821 :
2822 1992 : ++nOKBands;
2823 : }
2824 :
2825 929 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2826 929 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2827 :
2828 929 : CPLErr eErr = CE_None;
2829 929 : if (nOKBands > 0)
2830 : {
2831 886 : if (nOKBands < nBandCount)
2832 : {
2833 617 : psExtraArg->pfnProgress = GDALScaledProgress;
2834 1234 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2835 617 : 0.0, static_cast<double>(nOKBands) / nBandCount,
2836 : pfnProgressGlobal, pProgressDataGlobal);
2837 617 : if (psExtraArg->pProgressData == nullptr)
2838 228 : psExtraArg->pfnProgress = nullptr;
2839 : }
2840 :
2841 886 : eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2842 : pData, nBufXSize, nBufYSize, eBufType,
2843 : nOKBands, panBandMap, nPixelSpace,
2844 : nLineSpace, nBandSpace, psExtraArg);
2845 :
2846 886 : if (nOKBands < nBandCount)
2847 : {
2848 617 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2849 : }
2850 : }
2851 929 : if (eErr == CE_None && nOKBands < nBandCount)
2852 : {
2853 657 : if (nOKBands > 0)
2854 : {
2855 614 : psExtraArg->pfnProgress = GDALScaledProgress;
2856 1228 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2857 614 : static_cast<double>(nOKBands) / nBandCount, 1.0,
2858 : pfnProgressGlobal, pProgressDataGlobal);
2859 614 : if (psExtraArg->pProgressData == nullptr)
2860 225 : psExtraArg->pfnProgress = nullptr;
2861 : }
2862 1314 : eErr = BandBasedRasterIO(
2863 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
2864 657 : static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2865 : nBufYSize, eBufType, nBandCount - nOKBands,
2866 657 : panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2867 : psExtraArg);
2868 657 : if (nOKBands > 0)
2869 : {
2870 614 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2871 : }
2872 : }
2873 :
2874 929 : psExtraArg->pfnProgress = pfnProgressGlobal;
2875 929 : psExtraArg->pProgressData = pProgressDataGlobal;
2876 :
2877 929 : return eErr;
2878 : }
2879 :
2880 379766 : return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2881 : nBufXSize, nBufYSize, eBufType, nBandCount,
2882 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2883 379766 : psExtraArg);
2884 : }
2885 :
2886 : //! @endcond
2887 :
2888 : /************************************************************************/
2889 : /* BandBasedRasterIO() */
2890 : /* */
2891 : /* Pass the request off to each band objects rasterio methods with */
2892 : /* appropriate arguments. */
2893 : /************************************************************************/
2894 :
2895 : //! @cond Doxygen_Suppress
2896 652980 : CPLErr GDALDataset::BandBasedRasterIO(
2897 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2898 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2899 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2900 : GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2901 :
2902 : {
2903 : int iBandIndex;
2904 652980 : CPLErr eErr = CE_None;
2905 :
2906 652980 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2907 652980 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2908 :
2909 1692830 : for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2910 : ++iBandIndex)
2911 : {
2912 1039850 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2913 :
2914 1039850 : if (poBand == nullptr)
2915 : {
2916 0 : eErr = CE_Failure;
2917 0 : break;
2918 : }
2919 :
2920 1039850 : GByte *pabyBandData =
2921 1039850 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2922 :
2923 1039850 : if (nBandCount > 1)
2924 : {
2925 570384 : psExtraArg->pfnProgress = GDALScaledProgress;
2926 1140770 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2927 : 1.0 * iBandIndex / nBandCount,
2928 570384 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2929 : pProgressDataGlobal);
2930 570384 : if (psExtraArg->pProgressData == nullptr)
2931 567369 : psExtraArg->pfnProgress = nullptr;
2932 : }
2933 :
2934 2079700 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2935 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2936 1039850 : nPixelSpace, nLineSpace, psExtraArg);
2937 :
2938 1039850 : if (nBandCount > 1)
2939 570384 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2940 : }
2941 :
2942 652980 : psExtraArg->pfnProgress = pfnProgressGlobal;
2943 652980 : psExtraArg->pProgressData = pProgressDataGlobal;
2944 :
2945 652980 : return eErr;
2946 : }
2947 :
2948 : //! @endcond
2949 :
2950 : /************************************************************************/
2951 : /* ValidateRasterIOOrAdviseReadParameters() */
2952 : /************************************************************************/
2953 :
2954 : //! @cond Doxygen_Suppress
2955 750371 : CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2956 : const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2957 : int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2958 : int nBandCount, const int *panBandMap)
2959 : {
2960 :
2961 : /* -------------------------------------------------------------------- */
2962 : /* Some size values are "noop". Lets just return to avoid */
2963 : /* stressing lower level functions. */
2964 : /* -------------------------------------------------------------------- */
2965 750371 : if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2966 : {
2967 27 : CPLDebug("GDAL",
2968 : "%s skipped for odd window or buffer size.\n"
2969 : " Window = (%d,%d)x%dx%d\n"
2970 : " Buffer = %dx%d",
2971 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2972 : nBufYSize);
2973 :
2974 27 : *pbStopProcessingOnCENone = TRUE;
2975 27 : return CE_None;
2976 : }
2977 :
2978 750344 : CPLErr eErr = CE_None;
2979 750344 : *pbStopProcessingOnCENone = FALSE;
2980 :
2981 750344 : if (nXOff < 0 || nXOff > INT_MAX - nXSize ||
2982 750343 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
2983 750342 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize)
2984 : {
2985 2 : ReportError(CE_Failure, CPLE_IllegalArg,
2986 : "Access window out of range in %s. Requested "
2987 : "(%d,%d) of size %dx%d on raster of %dx%d.",
2988 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2989 : nRasterYSize);
2990 2 : eErr = CE_Failure;
2991 : }
2992 :
2993 750344 : if (panBandMap == nullptr && nBandCount > GetRasterCount())
2994 : {
2995 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2996 : "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2997 : GetRasterCount());
2998 0 : eErr = CE_Failure;
2999 : }
3000 :
3001 2250340 : for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
3002 : {
3003 1499990 : int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
3004 1499990 : if (iBand < 1 || iBand > GetRasterCount())
3005 : {
3006 3 : ReportError(
3007 : CE_Failure, CPLE_IllegalArg,
3008 : "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
3009 : pszCallingFunc, i, iBand);
3010 3 : eErr = CE_Failure;
3011 : }
3012 :
3013 1499990 : if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3014 : {
3015 0 : ReportError(
3016 : CE_Failure, CPLE_IllegalArg,
3017 : "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3018 : pszCallingFunc, i, iBand);
3019 0 : eErr = CE_Failure;
3020 : }
3021 : }
3022 :
3023 750344 : return eErr;
3024 : }
3025 :
3026 : //! @endcond
3027 :
3028 : /************************************************************************/
3029 : /* RasterIO() */
3030 : /************************************************************************/
3031 :
3032 : /**
3033 : * \brief Read/write a region of image data from multiple bands.
3034 : *
3035 : * This method allows reading a region of one or more GDALRasterBands from
3036 : * this dataset into a buffer, or writing data from a buffer into a region
3037 : * of the GDALRasterBands. It automatically takes care of data type
3038 : * translation if the data type (eBufType) of the buffer is different than
3039 : * that of the GDALRasterBand.
3040 : * The method also takes care of image decimation / replication if the
3041 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
3042 : * region being accessed (nXSize x nYSize).
3043 : *
3044 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3045 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3046 : * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3047 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
3048 : * Or use nLineSpace and a possibly shifted pData value.
3049 : *
3050 : * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3051 : * writing from various organization of buffers.
3052 : *
3053 : * Some formats may efficiently implement decimation into a buffer by
3054 : * reading from lower resolution overview images. The logic of the default
3055 : * implementation in the base class GDALRasterBand is the following one. It
3056 : * computes a target_downscaling_factor from the window of interest and buffer
3057 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3058 : * It then walks through overviews and will select the first one whose
3059 : * downscaling factor is greater than target_downscaling_factor / 1.2.
3060 : *
3061 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3062 : * The relationship between target_downscaling_factor and the select overview
3063 : * level is the following one:
3064 : *
3065 : * target_downscaling_factor | selected_overview
3066 : * ------------------------- | -----------------
3067 : * ]0, 2 / 1.2] | full resolution band
3068 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
3069 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
3070 : * ]8 / 1.2, infinity[ | 8x downsampled band
3071 : *
3072 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3073 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3074 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3075 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3076 : * this oversampling threshold defaults to 1. Consequently if there are overviews
3077 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3078 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3079 : *
3080 : * For highest performance full resolution data access, read and write
3081 : * on "block boundaries" as returned by GetBlockSize(), or use the
3082 : * ReadBlock() and WriteBlock() methods.
3083 : *
3084 : * This method is the same as the C GDALDatasetRasterIO() or
3085 : * GDALDatasetRasterIOEx() functions.
3086 : *
3087 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3088 : * write a region of data.
3089 : *
3090 : * @param nXOff The pixel offset to the top left corner of the region
3091 : * of the band to be accessed. This would be zero to start from the left side.
3092 : *
3093 : * @param nYOff The line offset to the top left corner of the region
3094 : * of the band to be accessed. This would be zero to start from the top.
3095 : *
3096 : * @param nXSize The width of the region of the band to be accessed in pixels.
3097 : *
3098 : * @param nYSize The height of the region of the band to be accessed in lines.
3099 : *
3100 : * @param pData The buffer into which the data should be read, or from which
3101 : * it should be written. This buffer must contain at least
3102 : * nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized
3103 : * in left to right,top to bottom pixel order. Spacing is controlled by the
3104 : * nPixelSpace, and nLineSpace parameters.
3105 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3106 : * temporarily modified during the execution of this method (and eventually
3107 : * restored back to its original content), so it is not safe to use a buffer
3108 : * stored in a read-only section of the calling program.
3109 : *
3110 : * @param nBufXSize the width of the buffer image into which the desired region
3111 : * is to be read, or from which it is to be written.
3112 : *
3113 : * @param nBufYSize the height of the buffer image into which the desired
3114 : * region is to be read, or from which it is to be written.
3115 : *
3116 : * @param eBufType the type of the pixel values in the pData data buffer. The
3117 : * pixel values will automatically be translated to/from the GDALRasterBand
3118 : * data type as needed. Most driver implementations will use GDALCopyWords64()
3119 : * to perform data type translation.
3120 : *
3121 : * @param nBandCount the number of bands being read or written.
3122 : *
3123 : * @param panBandMap the list of nBandCount band numbers being read/written.
3124 : * Note band numbers are 1 based. This may be NULL to select the first
3125 : * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3126 : * not "const int*")
3127 : *
3128 : * @param nPixelSpace The byte offset from the start of one pixel value in
3129 : * pData to the start of the next pixel value within a scanline. If defaulted
3130 : * (0) the size of the datatype eBufType is used.
3131 : *
3132 : * @param nLineSpace The byte offset from the start of one scanline in
3133 : * pData to the start of the next. If defaulted (0) the size of the datatype
3134 : * eBufType * nBufXSize is used.
3135 : *
3136 : * @param nBandSpace the byte offset from the start of one bands data to the
3137 : * start of the next. If defaulted (0) the value will be
3138 : * nLineSpace * nBufYSize implying band sequential organization
3139 : * of the data buffer.
3140 : *
3141 : * @param psExtraArg pointer to a GDALRasterIOExtraArg
3142 : * structure with additional arguments to specify resampling and progress
3143 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3144 : * configuration option can also be defined to override the default resampling
3145 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3146 : *
3147 : * @return CE_Failure if the access fails, otherwise CE_None.
3148 : */
3149 :
3150 735135 : CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3151 : int nXSize, int nYSize, void *pData, int nBufXSize,
3152 : int nBufYSize, GDALDataType eBufType,
3153 : int nBandCount, const int *panBandMap,
3154 : GSpacing nPixelSpace, GSpacing nLineSpace,
3155 : GSpacing nBandSpace,
3156 : GDALRasterIOExtraArg *psExtraArg)
3157 :
3158 : {
3159 : GDALRasterIOExtraArg sExtraArg;
3160 735135 : if (psExtraArg == nullptr)
3161 : {
3162 542182 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3163 :
3164 : // 4 below inits are not strictly needed but make Coverity Scan
3165 : // happy
3166 542182 : sExtraArg.dfXOff = nXOff;
3167 542182 : sExtraArg.dfYOff = nYOff;
3168 542182 : sExtraArg.dfXSize = nXSize;
3169 542182 : sExtraArg.dfYSize = nYSize;
3170 :
3171 542182 : psExtraArg = &sExtraArg;
3172 : }
3173 192953 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
3174 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3175 : {
3176 0 : ReportError(CE_Failure, CPLE_AppDefined,
3177 : "Unhandled version of GDALRasterIOExtraArg");
3178 0 : return CE_Failure;
3179 : }
3180 :
3181 735135 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3182 : nBufYSize);
3183 :
3184 735135 : if (CPL_UNLIKELY(nullptr == pData))
3185 : {
3186 0 : ReportError(CE_Failure, CPLE_AppDefined,
3187 : "The buffer into which the data should be read is null");
3188 0 : return CE_Failure;
3189 : }
3190 :
3191 : /* -------------------------------------------------------------------- */
3192 : /* Do some validation of parameters. */
3193 : /* -------------------------------------------------------------------- */
3194 :
3195 735135 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3196 : {
3197 0 : ReportError(
3198 : CE_Failure, CPLE_IllegalArg,
3199 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3200 : eRWFlag);
3201 0 : return CE_Failure;
3202 : }
3203 :
3204 735135 : if (eRWFlag == GF_Write)
3205 : {
3206 216560 : if (CPL_UNLIKELY(eAccess != GA_Update))
3207 : {
3208 2 : ReportError(CE_Failure, CPLE_AppDefined,
3209 : "Write operation not permitted on dataset opened "
3210 : "in read-only mode");
3211 2 : return CE_Failure;
3212 : }
3213 : }
3214 :
3215 735133 : int bStopProcessing = FALSE;
3216 735133 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3217 : "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3218 : nBufYSize, nBandCount, panBandMap);
3219 735133 : if (eErr != CE_None || bStopProcessing)
3220 9 : return eErr;
3221 735124 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3222 : {
3223 2 : ReportError(CE_Failure, CPLE_AppDefined,
3224 : "Illegal GDT_Unknown/GDT_TypeCount argument");
3225 2 : return CE_Failure;
3226 : }
3227 :
3228 : /* -------------------------------------------------------------------- */
3229 : /* If pixel and line spacing are defaulted assign reasonable */
3230 : /* value assuming a packed buffer. */
3231 : /* -------------------------------------------------------------------- */
3232 735122 : if (nPixelSpace == 0)
3233 424302 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3234 :
3235 735122 : if (nLineSpace == 0)
3236 : {
3237 481617 : nLineSpace = nPixelSpace * nBufXSize;
3238 : }
3239 :
3240 735122 : if (nBandSpace == 0 && nBandCount > 1)
3241 : {
3242 66905 : nBandSpace = nLineSpace * nBufYSize;
3243 : }
3244 :
3245 735122 : if (panBandMap == nullptr)
3246 : {
3247 359140 : if (!m_poPrivate)
3248 0 : return CE_Failure;
3249 359140 : CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3250 359140 : panBandMap = m_poPrivate->m_anBandMap.data();
3251 : }
3252 :
3253 735122 : int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3254 :
3255 : /* -------------------------------------------------------------------- */
3256 : /* We are being forced to use cached IO instead of a driver */
3257 : /* specific implementation. */
3258 : /* -------------------------------------------------------------------- */
3259 735122 : if (bForceCachedIO)
3260 : {
3261 21 : eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3262 : nBufXSize, nBufYSize, eBufType, nBandCount,
3263 : panBandMap, nPixelSpace, nLineSpace,
3264 21 : nBandSpace, psExtraArg);
3265 : }
3266 :
3267 : /* -------------------------------------------------------------------- */
3268 : /* Call the format specific function. */
3269 : /* -------------------------------------------------------------------- */
3270 : else
3271 : {
3272 735101 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3273 : nBufXSize, nBufYSize, eBufType, nBandCount,
3274 : // TODO: remove this const_cast once IRasterIO()
3275 : // takes a const int*
3276 : const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3277 735101 : nBandSpace, psExtraArg);
3278 : }
3279 :
3280 735122 : if (bCallLeaveReadWrite)
3281 407675 : LeaveReadWrite();
3282 :
3283 735122 : return eErr;
3284 : }
3285 :
3286 : /************************************************************************/
3287 : /* GDALDatasetRasterIO() */
3288 : /************************************************************************/
3289 :
3290 : /**
3291 : * \brief Read/write a region of image data from multiple bands.
3292 : *
3293 : * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3294 : * resolution, progress callback, etc. are needed)
3295 : *
3296 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3297 : *
3298 : * @see GDALDataset::RasterIO()
3299 : */
3300 :
3301 4762 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3302 : int nXOff, int nYOff, int nXSize,
3303 : int nYSize, void *pData, int nBufXSize,
3304 : int nBufYSize, GDALDataType eBufType,
3305 : int nBandCount, const int *panBandMap,
3306 : int nPixelSpace, int nLineSpace,
3307 : int nBandSpace)
3308 :
3309 : {
3310 4762 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3311 :
3312 4762 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3313 :
3314 4762 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3315 : nBufXSize, nBufYSize, eBufType, nBandCount,
3316 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3317 4762 : nullptr);
3318 : }
3319 :
3320 : /************************************************************************/
3321 : /* GDALDatasetRasterIOEx() */
3322 : /************************************************************************/
3323 :
3324 : /**
3325 : * \brief Read/write a region of image data from multiple bands.
3326 : *
3327 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3328 : *
3329 : * @see GDALDataset::RasterIO()
3330 : */
3331 :
3332 353278 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3333 : GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3334 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
3335 : GDALDataType eBufType, int nBandCount, const int *panBandMap,
3336 : GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3337 : GDALRasterIOExtraArg *psExtraArg)
3338 :
3339 : {
3340 353278 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3341 :
3342 353278 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3343 :
3344 353278 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3345 : nBufXSize, nBufYSize, eBufType, nBandCount,
3346 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3347 353278 : psExtraArg);
3348 : }
3349 :
3350 : /************************************************************************/
3351 : /* GetOpenDatasets() */
3352 : /************************************************************************/
3353 :
3354 : /**
3355 : * \brief Fetch all open GDAL dataset handles.
3356 : *
3357 : * This method is the same as the C function GDALGetOpenDatasets().
3358 : *
3359 : * NOTE: This method is not thread safe. The returned list may change
3360 : * at any time and it should not be freed.
3361 : *
3362 : * @param pnCount integer into which to place the count of dataset pointers
3363 : * being returned.
3364 : *
3365 : * @return a pointer to an array of dataset handles.
3366 : */
3367 :
3368 2268 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3369 :
3370 : {
3371 4536 : CPLMutexHolderD(&hDLMutex);
3372 :
3373 2268 : if (poAllDatasetMap == nullptr)
3374 : {
3375 2246 : *pnCount = 0;
3376 2246 : return nullptr;
3377 : }
3378 :
3379 22 : *pnCount = static_cast<int>(poAllDatasetMap->size());
3380 22 : ppDatasets = static_cast<GDALDataset **>(
3381 22 : CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3382 22 : std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3383 606 : for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3384 584 : ppDatasets[i] = oIter->first;
3385 22 : return ppDatasets;
3386 : }
3387 :
3388 : /************************************************************************/
3389 : /* GDALGetOpenDatasets() */
3390 : /************************************************************************/
3391 :
3392 : /**
3393 : * \brief Fetch all open GDAL dataset handles.
3394 : *
3395 : * @see GDALDataset::GetOpenDatasets()
3396 : */
3397 :
3398 0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3399 :
3400 : {
3401 0 : VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3402 0 : VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3403 :
3404 0 : *ppahDSList =
3405 0 : reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3406 : }
3407 :
3408 : /************************************************************************/
3409 : /* GDALCleanOpenDatasetsList() */
3410 : /************************************************************************/
3411 :
3412 : // Useful when called from the child of a fork(), to avoid closing
3413 : // the datasets of the parent at the child termination.
3414 0 : void GDALNullifyOpenDatasetsList()
3415 : {
3416 0 : poAllDatasetMap = nullptr;
3417 0 : phSharedDatasetSet = nullptr;
3418 0 : ppDatasets = nullptr;
3419 0 : hDLMutex = nullptr;
3420 0 : }
3421 :
3422 : /************************************************************************/
3423 : /* GDALGetAccess() */
3424 : /************************************************************************/
3425 :
3426 : /**
3427 : * \brief Return access flag
3428 : *
3429 : * @see GDALDataset::GetAccess()
3430 : */
3431 :
3432 0 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3433 : {
3434 0 : VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3435 :
3436 0 : return GDALDataset::FromHandle(hDS)->GetAccess();
3437 : }
3438 :
3439 : /************************************************************************/
3440 : /* AdviseRead() */
3441 : /************************************************************************/
3442 :
3443 : /**
3444 : * \brief Advise driver of upcoming read requests.
3445 : *
3446 : * Some GDAL drivers operate more efficiently if they know in advance what
3447 : * set of upcoming read requests will be made. The AdviseRead() method allows
3448 : * an application to notify the driver of the region and bands of interest,
3449 : * and at what resolution the region will be read.
3450 : *
3451 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
3452 : * accelerate access via some drivers.
3453 : *
3454 : * Depending on call paths, drivers might receive several calls to
3455 : * AdviseRead() with the same parameters.
3456 : *
3457 : * @param nXOff The pixel offset to the top left corner of the region
3458 : * of the band to be accessed. This would be zero to start from the left side.
3459 : *
3460 : * @param nYOff The line offset to the top left corner of the region
3461 : * of the band to be accessed. This would be zero to start from the top.
3462 : *
3463 : * @param nXSize The width of the region of the band to be accessed in pixels.
3464 : *
3465 : * @param nYSize The height of the region of the band to be accessed in lines.
3466 : *
3467 : * @param nBufXSize the width of the buffer image into which the desired region
3468 : * is to be read, or from which it is to be written.
3469 : *
3470 : * @param nBufYSize the height of the buffer image into which the desired
3471 : * region is to be read, or from which it is to be written.
3472 : *
3473 : * @param eBufType the type of the pixel values in the pData data buffer. The
3474 : * pixel values will automatically be translated to/from the GDALRasterBand
3475 : * data type as needed.
3476 : *
3477 : * @param nBandCount the number of bands being read or written.
3478 : *
3479 : * @param panBandMap the list of nBandCount band numbers being read/written.
3480 : * Note band numbers are 1 based. This may be NULL to select the first
3481 : * nBandCount bands.
3482 : *
3483 : * @param papszOptions a list of name=value strings with special control
3484 : * options. Normally this is NULL.
3485 : *
3486 : * @return CE_Failure if the request is invalid and CE_None if it works or
3487 : * is ignored.
3488 : */
3489 :
3490 14989 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3491 : int nBufXSize, int nBufYSize,
3492 : GDALDataType eBufType, int nBandCount,
3493 : int *panBandMap, char **papszOptions)
3494 :
3495 : {
3496 : /* -------------------------------------------------------------------- */
3497 : /* Do some validation of parameters. */
3498 : /* -------------------------------------------------------------------- */
3499 14989 : int bStopProcessing = FALSE;
3500 14989 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3501 : "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3502 : nBufXSize, nBufYSize, nBandCount, panBandMap);
3503 14989 : if (eErr != CE_None || bStopProcessing)
3504 23 : return eErr;
3505 :
3506 129197 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3507 : {
3508 114231 : GDALRasterBand *poBand = nullptr;
3509 :
3510 114231 : if (panBandMap == nullptr)
3511 112871 : poBand = GetRasterBand(iBand + 1);
3512 : else
3513 1360 : poBand = GetRasterBand(panBandMap[iBand]);
3514 :
3515 114231 : if (poBand == nullptr)
3516 0 : return CE_Failure;
3517 :
3518 228462 : eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3519 114231 : nBufYSize, eBufType, papszOptions);
3520 :
3521 114231 : if (eErr != CE_None)
3522 0 : return eErr;
3523 : }
3524 :
3525 14966 : return CE_None;
3526 : }
3527 :
3528 : /************************************************************************/
3529 : /* GDALDatasetAdviseRead() */
3530 : /************************************************************************/
3531 :
3532 : /**
3533 : * \brief Advise driver of upcoming read requests.
3534 : *
3535 : * @see GDALDataset::AdviseRead()
3536 : */
3537 1 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3538 : int nXSize, int nYSize, int nBufXSize,
3539 : int nBufYSize, GDALDataType eDT,
3540 : int nBandCount, int *panBandMap,
3541 : CSLConstList papszOptions)
3542 :
3543 : {
3544 1 : VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3545 :
3546 2 : return GDALDataset::FromHandle(hDS)->AdviseRead(
3547 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3548 1 : panBandMap, const_cast<char **>(papszOptions));
3549 : }
3550 :
3551 : /************************************************************************/
3552 : /* GDALAntiRecursionStruct */
3553 : /************************************************************************/
3554 :
3555 : // Prevent infinite recursion.
3556 : struct GDALAntiRecursionStruct
3557 : {
3558 : struct DatasetContext
3559 : {
3560 : std::string osFilename;
3561 : int nOpenFlags;
3562 : std::string osAllowedDrivers;
3563 :
3564 82367 : DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3565 : const std::string &osAllowedDriversIn)
3566 82367 : : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3567 82367 : osAllowedDrivers(osAllowedDriversIn)
3568 : {
3569 82367 : }
3570 : };
3571 :
3572 : struct DatasetContextCompare
3573 : {
3574 965343 : bool operator()(const DatasetContext &lhs,
3575 : const DatasetContext &rhs) const
3576 : {
3577 2821010 : return lhs.osFilename < rhs.osFilename ||
3578 934619 : (lhs.osFilename == rhs.osFilename &&
3579 921050 : (lhs.nOpenFlags < rhs.nOpenFlags ||
3580 1841640 : (lhs.nOpenFlags == rhs.nOpenFlags &&
3581 1886100 : lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3582 : }
3583 : };
3584 :
3585 1359 : ~GDALAntiRecursionStruct()
3586 1359 : {
3587 1359 : CPLAssert(aosDatasetNamesWithFlags.empty());
3588 1359 : CPLAssert(nRecLevel == 0);
3589 1359 : CPLAssert(m_oMapDepth.empty());
3590 1359 : }
3591 :
3592 : std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3593 : int nRecLevel = 0;
3594 : std::map<std::string, int> m_oMapDepth{};
3595 : };
3596 :
3597 : #ifdef _WIN32
3598 : // Currently thread_local and C++ objects don't work well with DLL on Windows
3599 : static void FreeAntiRecursionOpen(void *pData)
3600 : {
3601 : delete static_cast<GDALAntiRecursionStruct *>(pData);
3602 : }
3603 :
3604 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3605 : {
3606 : static GDALAntiRecursionStruct dummy;
3607 : int bMemoryErrorOccurred = false;
3608 : void *pData =
3609 : CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3610 : if (bMemoryErrorOccurred)
3611 : {
3612 : return dummy;
3613 : }
3614 : if (pData == nullptr)
3615 : {
3616 : auto pAntiRecursion = new GDALAntiRecursionStruct();
3617 : CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3618 : FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3619 : if (bMemoryErrorOccurred)
3620 : {
3621 : delete pAntiRecursion;
3622 : return dummy;
3623 : }
3624 : return *pAntiRecursion;
3625 : }
3626 : return *static_cast<GDALAntiRecursionStruct *>(pData);
3627 : }
3628 : #else
3629 : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3630 :
3631 346974 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3632 : {
3633 346974 : return g_tls_antiRecursion;
3634 : }
3635 : #endif
3636 :
3637 : //! @cond Doxygen_Suppress
3638 264607 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3639 264607 : : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3640 : m_osIdentifier(osIdentifier),
3641 264607 : m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3642 : {
3643 264607 : CPLAssert(!osIdentifier.empty());
3644 264607 : }
3645 :
3646 264607 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3647 264607 : const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3648 264607 : : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3649 264607 : m_osIdentifier(osIdentifier.empty()
3650 : ? osIdentifier
3651 30574 : : other.m_osIdentifier + osIdentifier),
3652 264607 : m_nDepth(m_osIdentifier.empty()
3653 264607 : ? 0
3654 295181 : : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3655 : {
3656 264607 : }
3657 :
3658 529214 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3659 : {
3660 529214 : if (!m_osIdentifier.empty())
3661 : {
3662 295181 : auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3663 295181 : CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3664 295181 : if (--(oIter->second) == 0)
3665 290729 : m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3666 : }
3667 529214 : }
3668 :
3669 : //! @endcond
3670 :
3671 : /************************************************************************/
3672 : /* GetFileList() */
3673 : /************************************************************************/
3674 :
3675 : /**
3676 : * \brief Fetch files forming dataset.
3677 : *
3678 : * Returns a list of files believed to be part of this dataset. If it returns
3679 : * an empty list of files it means there is believed to be no local file
3680 : * system files associated with the dataset (for instance a virtual dataset).
3681 : * The returned file list is owned by the caller and should be deallocated
3682 : * with CSLDestroy().
3683 : *
3684 : * The returned filenames will normally be relative or absolute paths
3685 : * depending on the path used to originally open the dataset. The strings
3686 : * will be UTF-8 encoded.
3687 : *
3688 : * This method is the same as the C GDALGetFileList() function.
3689 : *
3690 : * @return NULL or a NULL terminated array of file names.
3691 : */
3692 :
3693 4685 : char **GDALDataset::GetFileList()
3694 :
3695 : {
3696 9370 : CPLString osMainFilename = GetDescription();
3697 : VSIStatBufL sStat;
3698 :
3699 4685 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3700 : GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3701 9370 : std::string());
3702 4685 : auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3703 4685 : if (cpl::contains(aosDatasetList, datasetCtxt))
3704 0 : return nullptr;
3705 :
3706 : /* -------------------------------------------------------------------- */
3707 : /* Is the main filename even a real filesystem object? */
3708 : /* -------------------------------------------------------------------- */
3709 : int bMainFileReal =
3710 4685 : VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3711 :
3712 : /* -------------------------------------------------------------------- */
3713 : /* Form new list. */
3714 : /* -------------------------------------------------------------------- */
3715 4685 : char **papszList = nullptr;
3716 :
3717 4685 : if (bMainFileReal)
3718 4605 : papszList = CSLAddString(papszList, osMainFilename);
3719 :
3720 4685 : if (sAntiRecursion.nRecLevel == 100)
3721 : {
3722 0 : CPLError(CE_Failure, CPLE_AppDefined,
3723 : "GetFileList() called with too many recursion levels");
3724 0 : return papszList;
3725 : }
3726 4685 : ++sAntiRecursion.nRecLevel;
3727 :
3728 : /* -------------------------------------------------------------------- */
3729 : /* Do we have a known overview file? */
3730 : /* -------------------------------------------------------------------- */
3731 4685 : if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3732 : {
3733 60 : auto iter = aosDatasetList.insert(datasetCtxt).first;
3734 60 : char **papszOvrList = oOvManager.poODS->GetFileList();
3735 60 : papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3736 60 : CSLDestroy(papszOvrList);
3737 60 : aosDatasetList.erase(iter);
3738 : }
3739 :
3740 : /* -------------------------------------------------------------------- */
3741 : /* Do we have a known mask file? */
3742 : /* -------------------------------------------------------------------- */
3743 4685 : if (oOvManager.HaveMaskFile())
3744 : {
3745 9 : auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3746 9 : for (const char *pszFile :
3747 18 : CPLStringList(oOvManager.poMaskDS->GetFileList()))
3748 : {
3749 9 : if (CSLFindString(papszList, pszFile) < 0)
3750 9 : papszList = CSLAddString(papszList, pszFile);
3751 : }
3752 9 : aosDatasetList.erase(iter);
3753 : }
3754 :
3755 4685 : --sAntiRecursion.nRecLevel;
3756 :
3757 4685 : return papszList;
3758 : }
3759 :
3760 : /************************************************************************/
3761 : /* GDALGetFileList() */
3762 : /************************************************************************/
3763 :
3764 : /**
3765 : * \brief Fetch files forming dataset.
3766 : *
3767 : * @see GDALDataset::GetFileList()
3768 : */
3769 :
3770 3869 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3771 :
3772 : {
3773 3869 : VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3774 :
3775 3869 : return GDALDataset::FromHandle(hDS)->GetFileList();
3776 : }
3777 :
3778 : /************************************************************************/
3779 : /* CreateMaskBand() */
3780 : /************************************************************************/
3781 :
3782 : /**
3783 : * \brief Adds a mask band to the dataset
3784 : *
3785 : * The default implementation of the CreateMaskBand() method is implemented
3786 : * based on similar rules to the .ovr handling implemented using the
3787 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3788 : * be created with the same basename as the original file, and it will have
3789 : * one band.
3790 : * The mask images will be deflate compressed tiled images with the same
3791 : * block size as the original image if possible.
3792 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3793 : * level, where xx matches the band number of a band of the main dataset. The
3794 : * value of those items will be the one of the nFlagsIn parameter.
3795 : *
3796 : * Note that if you got a mask band with a previous call to GetMaskBand(), it
3797 : * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3798 : * again.
3799 : *
3800 : *
3801 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3802 : * GMF_PER_DATASET will be always set, even if not explicitly
3803 : * specified.
3804 : * @return CE_None on success or CE_Failure on an error.
3805 : *
3806 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3807 : * @see GDALRasterBand::CreateMaskBand()
3808 : *
3809 : */
3810 17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3811 :
3812 : {
3813 17 : if (oOvManager.IsInitialized())
3814 : {
3815 17 : CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3816 17 : if (eErr != CE_None)
3817 0 : return eErr;
3818 :
3819 : // Invalidate existing raster band masks.
3820 45 : for (int i = 0; i < nBands; ++i)
3821 : {
3822 28 : GDALRasterBand *poBand = papoBands[i];
3823 28 : poBand->poMask.reset();
3824 : }
3825 :
3826 17 : return CE_None;
3827 : }
3828 :
3829 0 : ReportError(CE_Failure, CPLE_NotSupported,
3830 : "CreateMaskBand() not supported for this dataset.");
3831 :
3832 0 : return CE_Failure;
3833 : }
3834 :
3835 : /************************************************************************/
3836 : /* GDALCreateDatasetMaskBand() */
3837 : /************************************************************************/
3838 :
3839 : /**
3840 : * \brief Adds a mask band to the dataset
3841 : * @see GDALDataset::CreateMaskBand()
3842 : */
3843 107 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3844 :
3845 : {
3846 107 : VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3847 :
3848 107 : return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3849 : }
3850 :
3851 : /************************************************************************/
3852 : /* GDALOpen() */
3853 : /************************************************************************/
3854 :
3855 : /**
3856 : * \brief Open a raster file as a GDALDataset.
3857 : *
3858 : * This function will try to open the passed file, or virtual dataset
3859 : * name by invoking the Open method of each registered GDALDriver in turn.
3860 : * The first successful open will result in a returned dataset. If all
3861 : * drivers fail then NULL is returned and an error is issued.
3862 : *
3863 : * Several recommendations :
3864 : * <ul>
3865 : * <li>If you open a dataset object with GA_Update access, it is not recommended
3866 : * to open a new dataset on the same underlying file.</li>
3867 : * <li>The returned dataset should only be accessed by one thread at a time. If
3868 : * you want to use it from different threads, you must add all necessary code
3869 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3870 : * as GeoTIFF, maintain internal state variables that are updated each time a
3871 : * new block is read, thus preventing concurrent use.) </li>
3872 : * </ul>
3873 : *
3874 : * For drivers supporting the VSI virtual file API, it is possible to open a
3875 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3876 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3877 : * server (see VSIInstallCurlFileHandler())
3878 : *
3879 : * \sa GDALOpenShared()
3880 : * \sa GDALOpenEx()
3881 : *
3882 : * @param pszFilename the name of the file to access. In the case of
3883 : * exotic drivers this may not refer to a physical file, but instead contain
3884 : * information for the driver on how to access a dataset. It should be in UTF-8
3885 : * encoding.
3886 : *
3887 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
3888 : * drivers support only read only access.
3889 : *
3890 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
3891 : * this handle can be cast to a GDALDataset *.
3892 : */
3893 :
3894 25543 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3895 :
3896 : {
3897 25543 : const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3898 25543 : const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3899 : GDALDatasetH hDataset =
3900 25543 : GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3901 25543 : return hDataset;
3902 : }
3903 :
3904 : /************************************************************************/
3905 : /* GetSharedDS() */
3906 : /************************************************************************/
3907 :
3908 6485 : static GDALDataset *GetSharedDS(const char *pszFilename,
3909 : unsigned int nOpenFlags,
3910 : const char *const *papszOpenOptions)
3911 : {
3912 12970 : CPLMutexHolderD(&hDLMutex);
3913 :
3914 6485 : if (phSharedDatasetSet != nullptr)
3915 : {
3916 6244 : const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3917 : SharedDatasetCtxt sStruct;
3918 :
3919 6244 : sStruct.nPID = nThisPID;
3920 6244 : sStruct.pszDescription = const_cast<char *>(pszFilename);
3921 6244 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3922 : std::string osConcatenatedOpenOptions =
3923 6244 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3924 6244 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3925 6244 : sStruct.poDS = nullptr;
3926 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3927 6244 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3928 6244 : if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3929 : {
3930 139 : sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3931 : psStruct = static_cast<SharedDatasetCtxt *>(
3932 139 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3933 : }
3934 6244 : if (psStruct)
3935 : {
3936 6106 : return psStruct->poDS;
3937 : }
3938 : }
3939 379 : return nullptr;
3940 : }
3941 :
3942 : /************************************************************************/
3943 : /* GDALOpenEx() */
3944 : /************************************************************************/
3945 :
3946 : /**
3947 : * \brief Open a raster or vector file as a GDALDataset.
3948 : *
3949 : * This function will try to open the passed file, or virtual dataset
3950 : * name by invoking the Open method of each registered GDALDriver in turn.
3951 : * The first successful open will result in a returned dataset. If all
3952 : * drivers fail then NULL is returned and an error is issued.
3953 : *
3954 : * Several recommendations :
3955 : * <ul>
3956 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3957 : * recommended to open a new dataset on the same underlying file.</li>
3958 : * <li>The returned dataset should only be accessed by one thread at a time. If
3959 : * you want to use it from different threads, you must add all necessary code
3960 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3961 : * as GeoTIFF, maintain internal state variables that are updated each time a
3962 : * new block is read, thus preventing concurrent use.) </li>
3963 : * </ul>
3964 : *
3965 : * For drivers supporting the VSI virtual file API, it is possible to open a
3966 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3967 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3968 : * server (see VSIInstallCurlFileHandler())
3969 : *
3970 : * In order to reduce the need for searches through the operating system
3971 : * file system machinery, it is possible to give an optional list of files with
3972 : * the papszSiblingFiles parameter.
3973 : * This is the list of all files at the same level in the file system as the
3974 : * target file, including the target file. The filenames must not include any
3975 : * path components, are essentially just the output of VSIReadDir() on the
3976 : * parent directory. If the target object does not have filesystem semantics
3977 : * then the file list should be NULL.
3978 : *
3979 : * @param pszFilename the name of the file to access. In the case of
3980 : * exotic drivers this may not refer to a physical file, but instead contain
3981 : * information for the driver on how to access a dataset. It should be in UTF-8
3982 : * encoding.
3983 : *
3984 : * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3985 : * through logical or operator.
3986 : * <ul>
3987 : * <li>Driver kind:
3988 : * <ul>
3989 : * <li>GDAL_OF_RASTER for raster drivers,</li>
3990 : * <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3991 : * <li>GDAL_OF_VECTOR for vector drivers,</li>
3992 : * <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3993 : * </ul>
3994 : * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3995 : * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3996 : * | GDAL_OF_GNM is implied.
3997 : * </li>
3998 : * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3999 : * </li>
4000 : * <li>Shared mode: GDAL_OF_SHARED. If set,
4001 : * it allows the sharing of GDALDataset handles for a dataset with other callers
4002 : * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
4003 : * its list of currently open and shared GDALDataset's, and if the
4004 : * GetDescription() name for one exactly matches the pszFilename passed to
4005 : * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
4006 : * from the same thread.
4007 : * </li>
4008 : * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
4009 : * This must be use in combination with GDAL_OF_RASTER, and is mutually
4010 : * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4011 : * GDAL_OF_GNM.
4012 : * </li>
4013 : * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4014 : * a failed attempt to open the file will lead to an error message to be
4015 : * reported.
4016 : * </li>
4017 : * </ul>
4018 : *
4019 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4020 : * terminated list of strings with the driver short names that must be
4021 : * considered.
4022 : *
4023 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4024 : * options passed to candidate drivers. An option exists for all drivers,
4025 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4026 : * The level index starts at 0. The level number can be suffixed by "only" to
4027 : * specify that only this overview level must be visible, and not sub-levels.
4028 : * Open options are validated by default, and a warning is emitted in case the
4029 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4030 : * when not knowing which driver will open the file), so the special open option
4031 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4032 : * that it may not cause a warning if the driver doesn't declare this option.
4033 : * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4034 : * no overviews should be exposed.
4035 : *
4036 : * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4037 : * filenames that are auxiliary to the main filename. If NULL is passed, a
4038 : * probing of the file system will be done.
4039 : *
4040 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4041 : * this handle can be cast to a GDALDataset *.
4042 : *
4043 : */
4044 :
4045 83792 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4046 : unsigned int nOpenFlags,
4047 : const char *const *papszAllowedDrivers,
4048 : const char *const *papszOpenOptions,
4049 : const char *const *papszSiblingFiles)
4050 : {
4051 83792 : VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4052 :
4053 : // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4054 : // into VSIKERCHUNK_USE_CACHE config option
4055 83792 : std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4056 83792 : if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4057 : {
4058 13 : poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4059 26 : "VSIKERCHUNK_USE_CACHE", "YES", false);
4060 : }
4061 :
4062 : // Do some sanity checks on incompatible flags with thread-safe mode.
4063 83792 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4064 : {
4065 : const struct
4066 : {
4067 : int nFlag;
4068 : const char *pszFlagName;
4069 128 : } asFlags[] = {
4070 : {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4071 : {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4072 : {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4073 : {GDAL_OF_GNM, "GDAL_OF_GNM"},
4074 : };
4075 :
4076 630 : for (const auto &asFlag : asFlags)
4077 : {
4078 506 : if ((nOpenFlags & asFlag.nFlag) != 0)
4079 : {
4080 4 : CPLError(CE_Failure, CPLE_IllegalArg,
4081 : "GDAL_OF_THREAD_SAFE and %s are mutually "
4082 : "exclusive",
4083 4 : asFlag.pszFlagName);
4084 4 : return nullptr;
4085 : }
4086 : }
4087 : }
4088 :
4089 : // If no driver kind is specified, assume all are to be probed.
4090 83788 : if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4091 7584 : nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4092 :
4093 : /* -------------------------------------------------------------------- */
4094 : /* In case of shared dataset, first scan the existing list to see */
4095 : /* if it could already contain the requested dataset. */
4096 : /* -------------------------------------------------------------------- */
4097 83788 : if (nOpenFlags & GDAL_OF_SHARED)
4098 : {
4099 6485 : if (nOpenFlags & GDAL_OF_INTERNAL)
4100 : {
4101 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4102 : "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4103 0 : return nullptr;
4104 : }
4105 :
4106 : auto poSharedDS =
4107 6485 : GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4108 6485 : if (poSharedDS)
4109 : {
4110 6106 : poSharedDS->Reference();
4111 6106 : return poSharedDS;
4112 : }
4113 : }
4114 :
4115 77682 : GDALDriverManager *poDM = GetGDALDriverManager();
4116 : // CPLLocaleC oLocaleForcer;
4117 :
4118 77682 : CPLErrorReset();
4119 77682 : VSIErrorReset();
4120 77682 : CPLAssert(nullptr != poDM);
4121 :
4122 : // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4123 : // shared dataset was asked before.
4124 : GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags,
4125 155364 : const_cast<char **>(papszSiblingFiles));
4126 77682 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4127 :
4128 77682 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4129 77682 : if (sAntiRecursion.nRecLevel == 100)
4130 : {
4131 0 : CPLError(CE_Failure, CPLE_AppDefined,
4132 : "GDALOpen() called with too many recursion levels");
4133 0 : return nullptr;
4134 : }
4135 :
4136 155364 : std::string osAllowedDrivers;
4137 169536 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4138 91854 : osAllowedDrivers += pszDriverName;
4139 : auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4140 233046 : std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4141 77682 : if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4142 : {
4143 0 : CPLError(CE_Failure, CPLE_AppDefined,
4144 : "GDALOpen() called on %s recursively", pszFilename);
4145 0 : return nullptr;
4146 : }
4147 :
4148 : // Remove leading @ if present.
4149 : char **papszOpenOptionsCleaned =
4150 77682 : CSLDuplicate(const_cast<char **>(papszOpenOptions));
4151 83311 : for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4152 : ++papszIter)
4153 : {
4154 5629 : char *pszOption = *papszIter;
4155 5629 : if (pszOption[0] == '@')
4156 212 : memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4157 : }
4158 :
4159 77682 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4160 77682 : oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4161 :
4162 : #ifdef OGRAPISPY_ENABLED
4163 77682 : const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4164 : const int iSnapshot =
4165 19389 : (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4166 97071 : ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4167 77682 : : INT_MIN;
4168 : #endif
4169 :
4170 77682 : const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4171 77682 : GDALDriver *poMissingPluginDriver = nullptr;
4172 155364 : std::vector<GDALDriver *> apoSecondPassDrivers;
4173 :
4174 : // Lookup of matching driver for dataset can involve up to 2 passes:
4175 : // - in the first pass, all drivers that are compabile of the request mode
4176 : // (raster/vector/etc.) are probed using their Identify() method if it
4177 : // exists. If the Identify() method returns FALSE, the driver is skipped.
4178 : // If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4179 : // driver is a deferred-loading plugin, it is added to the
4180 : // apoSecondPassDrivers list for potential later probing, and execution
4181 : // continues to the next driver in the list.
4182 : // Otherwise if Identify() returns non-FALSE, the Open() method is used.
4183 : // If Open() returns a non-NULL dataset, the loop stops and it is
4184 : // returned. Otherwise looping over remaining drivers continues.
4185 : // - the second pass is optional, only if at least one driver was added
4186 : // into apoSecondPassDrivers during the first pass. It is similar
4187 : // to the first pass except it runs only on apoSecondPassDrivers drivers.
4188 : // And the Open() method of such drivers is used, causing them to be
4189 : // loaded for real.
4190 77682 : int iPass = 1;
4191 77696 : retry:
4192 8030770 : for (int iDriver = 0;
4193 8030800 : iDriver < (iPass == 1 ? nDriverCount
4194 34 : : static_cast<int>(apoSecondPassDrivers.size()));
4195 : ++iDriver)
4196 : {
4197 : GDALDriver *poDriver =
4198 8011720 : iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4199 25 : : apoSecondPassDrivers[iDriver];
4200 11704500 : if (papszAllowedDrivers != nullptr &&
4201 3692820 : CSLFindString(papszAllowedDrivers,
4202 : GDALGetDriverShortName(poDriver)) == -1)
4203 : {
4204 7551410 : continue;
4205 : }
4206 :
4207 4405660 : if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4208 43195 : continue;
4209 :
4210 11572500 : if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4211 6309930 : (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4212 1947470 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4213 463734 : continue;
4214 11432500 : if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4215 5725340 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4216 1826610 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4217 1372020 : continue;
4218 5352890 : if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4219 2677710 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4220 151005 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4221 142065 : continue;
4222 :
4223 : // Remove general OVERVIEW_LEVEL open options from list before passing
4224 : // it to the driver, if it isn't a driver specific option already.
4225 2384640 : char **papszTmpOpenOptions = nullptr;
4226 2384640 : char **papszTmpOpenOptionsToValidate = nullptr;
4227 2384640 : char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4228 2384640 : if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4229 2384790 : nullptr &&
4230 152 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4231 : {
4232 152 : papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4233 : papszTmpOpenOptions =
4234 152 : CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4235 152 : oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4236 :
4237 152 : papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4238 152 : papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4239 : "OVERVIEW_LEVEL", nullptr);
4240 152 : papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4241 : }
4242 :
4243 : const int nIdentifyRes =
4244 2384640 : poDriver->pfnIdentifyEx
4245 4769270 : ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4246 2384630 : : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4247 2384640 : : GDAL_IDENTIFY_UNKNOWN;
4248 2384640 : if (nIdentifyRes == FALSE)
4249 : {
4250 1924260 : CSLDestroy(papszTmpOpenOptions);
4251 1924260 : CSLDestroy(papszTmpOpenOptionsToValidate);
4252 1924260 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4253 1924260 : continue;
4254 : }
4255 460359 : else if (iPass == 1 && nIdentifyRes < 0 &&
4256 920849 : poDriver->pfnOpen == nullptr &&
4257 106 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4258 : {
4259 : // Not loaded plugin
4260 104 : apoSecondPassDrivers.push_back(poDriver);
4261 104 : CSLDestroy(papszTmpOpenOptions);
4262 104 : CSLDestroy(papszTmpOpenOptionsToValidate);
4263 104 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4264 104 : continue;
4265 : }
4266 :
4267 460280 : const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4268 460280 : if (bIdentifyRes)
4269 : {
4270 57665 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4271 : }
4272 :
4273 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4274 : const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4275 : CPLErrorReset();
4276 : #endif
4277 :
4278 460280 : sAntiRecursion.nRecLevel++;
4279 460280 : sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4280 :
4281 460280 : GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4282 :
4283 460280 : sAntiRecursion.nRecLevel--;
4284 460280 : sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4285 :
4286 460280 : if (poDriver->pfnOpen != nullptr)
4287 : {
4288 : // If we couldn't determine for sure with Identify() (it returned
4289 : // -1), but Open() managed to open the file, post validate options.
4290 460277 : if (poDS != nullptr &&
4291 57577 : (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4292 57012 : !bIdentifyRes)
4293 : {
4294 815 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4295 : }
4296 : }
4297 3 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
4298 : {
4299 : // do nothing
4300 : }
4301 0 : else if (bIdentifyRes &&
4302 0 : poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4303 : {
4304 0 : if (!poMissingPluginDriver)
4305 : {
4306 0 : poMissingPluginDriver = poDriver;
4307 : }
4308 : }
4309 : else
4310 : {
4311 : // should not happen given the GDAL_DCAP_OPEN check
4312 0 : CSLDestroy(papszTmpOpenOptions);
4313 0 : CSLDestroy(papszTmpOpenOptionsToValidate);
4314 0 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4315 0 : continue;
4316 : }
4317 :
4318 460280 : CSLDestroy(papszTmpOpenOptions);
4319 460280 : CSLDestroy(papszTmpOpenOptionsToValidate);
4320 460280 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4321 :
4322 460280 : if (poDS != nullptr)
4323 : {
4324 57580 : if (poDS->papszOpenOptions == nullptr)
4325 : {
4326 57317 : poDS->papszOpenOptions = papszOpenOptionsCleaned;
4327 57317 : papszOpenOptionsCleaned = nullptr;
4328 : }
4329 :
4330 : // Deal with generic OVERVIEW_LEVEL open option, unless it is
4331 : // driver specific.
4332 57580 : if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4333 57619 : nullptr &&
4334 39 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4335 : {
4336 : CPLString osVal(
4337 78 : CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4338 39 : const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4339 : const bool bThisLevelOnly =
4340 39 : nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4341 : GDALDataset *poOvrDS =
4342 39 : GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4343 39 : if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4344 : {
4345 4 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4346 : {
4347 0 : CPLError(
4348 : CE_Warning, CPLE_NotSupported,
4349 : "A dataset opened by GDALOpenShared should have "
4350 : "the same filename (%s) "
4351 : "and description (%s)",
4352 0 : pszFilename, poDS->GetDescription());
4353 : }
4354 : else
4355 : {
4356 4 : CSLDestroy(poDS->papszOpenOptions);
4357 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4358 4 : poDS->papszOpenOptions = CSLSetNameValue(
4359 : poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4360 : }
4361 : }
4362 39 : poDS->ReleaseRef();
4363 39 : poDS = poOvrDS;
4364 39 : if (poDS == nullptr)
4365 : {
4366 1 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4367 : {
4368 1 : CPLError(CE_Failure, CPLE_OpenFailed,
4369 : "Cannot open overview level %d of %s",
4370 : nOvrLevel, pszFilename);
4371 : }
4372 : }
4373 : else
4374 : {
4375 : // For thread-safe opening, currently poDS is what will be
4376 : // the "master" dataset owned by the thread-safe dataset
4377 : // returned to the user, hence we do not register it as a
4378 : // visible one in the open dataset list, or mark it as shared.
4379 38 : if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4380 36 : !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4381 : {
4382 35 : poDS->AddToDatasetOpenList();
4383 : }
4384 38 : if (nOpenFlags & GDAL_OF_SHARED)
4385 : {
4386 4 : CSLDestroy(poDS->papszOpenOptions);
4387 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4388 4 : poDS->nOpenFlags = nOpenFlags;
4389 4 : if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4390 4 : poDS->MarkAsShared();
4391 : }
4392 : }
4393 : }
4394 57541 : else if (nOpenFlags & GDAL_OF_SHARED)
4395 : {
4396 369 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4397 : {
4398 2 : CPLError(CE_Warning, CPLE_NotSupported,
4399 : "A dataset opened by GDALOpenShared should have "
4400 : "the same filename (%s) "
4401 : "and description (%s)",
4402 2 : pszFilename, poDS->GetDescription());
4403 : }
4404 367 : else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4405 : {
4406 : // For thread-safe opening, currently poDS is what will be
4407 : // the "master" dataset owned by the thread-safe dataset
4408 : // returned to the user, hence we do not or mark it as shared.
4409 367 : poDS->MarkAsShared();
4410 : }
4411 : }
4412 :
4413 57580 : VSIErrorReset();
4414 :
4415 57580 : CSLDestroy(papszOpenOptionsCleaned);
4416 :
4417 : #ifdef OGRAPISPY_ENABLED
4418 57580 : if (iSnapshot != INT_MIN)
4419 : {
4420 11564 : GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4421 11564 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4422 11564 : poDS = GDALDataset::FromHandle(hDS);
4423 : }
4424 : #endif
4425 :
4426 57580 : if (poDS)
4427 : {
4428 57579 : poDS->m_bCanBeReopened = true;
4429 :
4430 57579 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4431 : {
4432 : poDS =
4433 248 : GDALGetThreadSafeDataset(
4434 248 : std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4435 124 : .release();
4436 124 : if (poDS)
4437 : {
4438 124 : poDS->m_bCanBeReopened = true;
4439 124 : poDS->poDriver = poDriver;
4440 124 : poDS->nOpenFlags = nOpenFlags;
4441 124 : if (!(nOpenFlags & GDAL_OF_INTERNAL))
4442 124 : poDS->AddToDatasetOpenList();
4443 124 : if (nOpenFlags & GDAL_OF_SHARED)
4444 0 : poDS->MarkAsShared();
4445 : }
4446 : }
4447 : }
4448 :
4449 58616 : return poDS;
4450 : }
4451 :
4452 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4453 : if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4454 : {
4455 : // In case the file descriptor was "consumed" by a driver
4456 : // that ultimately failed, re-open it for next drivers.
4457 : oOpenInfo.fpL = VSIFOpenL(
4458 : pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4459 : }
4460 : #else
4461 402700 : if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4462 : {
4463 1036 : CSLDestroy(papszOpenOptionsCleaned);
4464 :
4465 : #ifdef OGRAPISPY_ENABLED
4466 1036 : if (iSnapshot != INT_MIN)
4467 : {
4468 193 : GDALDatasetH hDS = nullptr;
4469 193 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4470 : }
4471 : #endif
4472 1036 : return nullptr;
4473 : }
4474 : #endif
4475 : }
4476 :
4477 : // cppcheck-suppress knownConditionTrueFalse
4478 19080 : if (iPass == 1 && !apoSecondPassDrivers.empty())
4479 : {
4480 14 : CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4481 14 : iPass = 2;
4482 14 : goto retry;
4483 : }
4484 :
4485 19066 : CSLDestroy(papszOpenOptionsCleaned);
4486 :
4487 : #ifdef OGRAPISPY_ENABLED
4488 19066 : if (iSnapshot != INT_MIN)
4489 : {
4490 654 : GDALDatasetH hDS = nullptr;
4491 654 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4492 : }
4493 : #endif
4494 :
4495 19066 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4496 : {
4497 5729 : if (nDriverCount == 0)
4498 : {
4499 0 : CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4500 : }
4501 5729 : else if (poMissingPluginDriver)
4502 : {
4503 0 : std::string osMsg("`");
4504 0 : osMsg += pszFilename;
4505 : osMsg += "' not recognized as being in a supported file format. "
4506 0 : "It could have been recognized by driver ";
4507 0 : osMsg += poMissingPluginDriver->GetDescription();
4508 0 : osMsg += ", but plugin ";
4509 : osMsg +=
4510 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4511 :
4512 0 : CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4513 : }
4514 : // Check to see if there was a filesystem error, and report it if so.
4515 : // If not, return a more generic error.
4516 5729 : else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4517 : {
4518 355 : if (oOpenInfo.bStatOK)
4519 : {
4520 352 : CPLError(CE_Failure, CPLE_OpenFailed,
4521 : "`%s' not recognized as being in a supported file "
4522 : "format.",
4523 : pszFilename);
4524 : }
4525 : else
4526 : {
4527 : // If Stat failed and no VSI error was set, assume it is because
4528 : // the file did not exist on the filesystem.
4529 3 : CPLError(CE_Failure, CPLE_OpenFailed,
4530 : "`%s' does not exist in the file system, "
4531 : "and is not recognized as a supported dataset name.",
4532 : pszFilename);
4533 : }
4534 : }
4535 : }
4536 :
4537 19066 : return nullptr;
4538 : }
4539 :
4540 : /************************************************************************/
4541 : /* GDALOpenShared() */
4542 : /************************************************************************/
4543 :
4544 : /**
4545 : * \brief Open a raster file as a GDALDataset.
4546 : *
4547 : * This function works the same as GDALOpen(), but allows the sharing of
4548 : * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4549 : *
4550 : * In particular, GDALOpenShared() will first consult its list of currently
4551 : * open and shared GDALDataset's, and if the GetDescription() name for one
4552 : * exactly matches the pszFilename passed to GDALOpenShared() it will be
4553 : * referenced and returned.
4554 : *
4555 : * If GDALOpenShared() is called on the same
4556 : * pszFilename from two different threads, a different GDALDataset object will
4557 : * be returned as it is not safe to use the same dataset from different threads,
4558 : * unless the user does explicitly use mutexes in its code.
4559 : *
4560 : * For drivers supporting the VSI virtual file API, it is possible to open a
4561 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4562 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4563 : * server (see VSIInstallCurlFileHandler())
4564 : *
4565 : * \sa GDALOpen()
4566 : * \sa GDALOpenEx()
4567 : *
4568 : * @param pszFilename the name of the file to access. In the case of
4569 : * exotic drivers this may not refer to a physical file, but instead contain
4570 : * information for the driver on how to access a dataset. It should be in
4571 : * UTF-8 encoding.
4572 : *
4573 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
4574 : * drivers support only read only access.
4575 : *
4576 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4577 : * this handle can be cast to a GDALDataset *.
4578 : */
4579 :
4580 5204 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4581 : GDALAccess eAccess)
4582 : {
4583 5204 : VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4584 5204 : return GDALOpenEx(pszFilename,
4585 : GDAL_OF_RASTER |
4586 : (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4587 : GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4588 5204 : nullptr, nullptr, nullptr);
4589 : }
4590 :
4591 : /************************************************************************/
4592 : /* GDALClose() */
4593 : /************************************************************************/
4594 :
4595 : /**
4596 : * \brief Close GDAL dataset.
4597 : *
4598 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4599 : * using the C++ "delete" operator, recovering all dataset related resources.
4600 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4601 : * dereferenced, and closed only if the referenced count has dropped below 1.
4602 : *
4603 : * @param hDS The dataset to close, or nullptr.
4604 : * @return CE_None in case of success (return value since GDAL 3.7). On a
4605 : * shared dataset whose reference count is not dropped below 1, CE_None will
4606 : * be returned.
4607 : *
4608 : * @see GDALCloseEx()
4609 : */
4610 :
4611 73317 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4612 :
4613 : {
4614 73317 : return GDALCloseEx(hDS, nullptr, nullptr);
4615 : }
4616 :
4617 : /************************************************************************/
4618 : /* GDALCloseEx() */
4619 : /************************************************************************/
4620 :
4621 : /**
4622 : * \brief Close GDAL dataset.
4623 : *
4624 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4625 : * using the C++ "delete" operator, recovering all dataset related resources.
4626 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4627 : * dereferenced, and closed only if the referenced count has dropped below 1.
4628 : *
4629 : * This function may report progress if a progress
4630 : * callback if provided in the pfnProgress argument and if the dataset returns
4631 : * true for GDALDataset::GetCloseReportsProgress()
4632 :
4633 : * @param hDS The dataset to close, or nullptr
4634 : * @param pfnProgress Progress callback, or nullptr
4635 : * @param pProgressData User data of progress callback, or nullptr
4636 : *
4637 : * @return CE_None in case of success. On a
4638 : * shared dataset whose reference count is not dropped below 1, CE_None will
4639 : * be returned.
4640 : *
4641 : * @since GDAL 3.13
4642 : * @see GDALClose()
4643 : */
4644 :
4645 77465 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4646 : void *pProgressData)
4647 : {
4648 77465 : if (!hDS)
4649 402 : return CE_None;
4650 :
4651 : #ifdef OGRAPISPY_ENABLED
4652 77063 : if (bOGRAPISpyEnabled)
4653 11 : OGRAPISpyPreClose(hDS);
4654 : #endif
4655 :
4656 77063 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4657 :
4658 77063 : if (poDS->GetShared())
4659 : {
4660 : /* --------------------------------------------------------------------
4661 : */
4662 : /* If this file is in the shared dataset list then dereference */
4663 : /* it, and only delete/remote it if the reference count has */
4664 : /* dropped to zero. */
4665 : /* --------------------------------------------------------------------
4666 : */
4667 236 : if (poDS->Dereference() > 0)
4668 15 : return CE_None;
4669 : }
4670 :
4671 77048 : CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4672 77048 : delete poDS;
4673 :
4674 : #ifdef OGRAPISPY_ENABLED
4675 77048 : if (bOGRAPISpyEnabled)
4676 11 : OGRAPISpyPostClose();
4677 : #endif
4678 77048 : return eErr;
4679 : }
4680 :
4681 : /************************************************************************/
4682 : /* GDALDumpOpenDataset() */
4683 : /************************************************************************/
4684 :
4685 0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4686 : {
4687 0 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4688 0 : FILE *fp = static_cast<FILE *>(user_data);
4689 0 : GDALDataset *poDS = psStruct->poDS;
4690 :
4691 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4692 0 : ? "DriverIsNULL"
4693 0 : : poDS->GetDriver()->GetDescription();
4694 :
4695 0 : poDS->Reference();
4696 0 : CPL_IGNORE_RET_VAL(
4697 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4698 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName,
4699 0 : static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4700 : poDS->GetRasterYSize(), poDS->GetRasterCount(),
4701 0 : poDS->GetDescription()));
4702 :
4703 0 : return TRUE;
4704 : }
4705 :
4706 0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4707 : {
4708 :
4709 : // Don't list shared datasets. They have already been listed by
4710 : // GDALDumpOpenSharedDatasetsForeach.
4711 0 : if (poDS->GetShared())
4712 0 : return TRUE;
4713 :
4714 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4715 0 : ? "DriverIsNULL"
4716 0 : : poDS->GetDriver()->GetDescription();
4717 :
4718 0 : poDS->Reference();
4719 0 : CPL_IGNORE_RET_VAL(
4720 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4721 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4722 : poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4723 0 : poDS->GetRasterCount(), poDS->GetDescription()));
4724 :
4725 0 : return TRUE;
4726 : }
4727 :
4728 : /**
4729 : * \brief List open datasets.
4730 : *
4731 : * Dumps a list of all open datasets (shared or not) to the indicated
4732 : * text file (may be stdout or stderr). This function is primarily intended
4733 : * to assist in debugging "dataset leaks" and reference counting issues.
4734 : * The information reported includes the dataset name, referenced count,
4735 : * shared status, driver name, size, and band count.
4736 : */
4737 :
4738 272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4739 :
4740 : {
4741 272 : VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4742 :
4743 544 : CPLMutexHolderD(&hDLMutex);
4744 :
4745 272 : if (poAllDatasetMap == nullptr)
4746 272 : return 0;
4747 :
4748 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4749 :
4750 0 : for (const auto &oIter : *poAllDatasetMap)
4751 : {
4752 0 : GDALDumpOpenDatasetsForeach(oIter.first, fp);
4753 : }
4754 :
4755 0 : if (phSharedDatasetSet != nullptr)
4756 : {
4757 0 : CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4758 : fp);
4759 : }
4760 0 : return static_cast<int>(poAllDatasetMap->size());
4761 : }
4762 :
4763 : /************************************************************************/
4764 : /* BeginAsyncReader() */
4765 : /************************************************************************/
4766 :
4767 : /**
4768 : * \brief Sets up an asynchronous data request
4769 : *
4770 : * This method establish an asynchronous raster read request for the
4771 : * indicated window on the dataset into the indicated buffer. The parameters
4772 : * for windowing, buffer size, buffer type and buffer organization are similar
4773 : * to those for GDALDataset::RasterIO(); however, this call only launches
4774 : * the request and filling the buffer is accomplished via calls to
4775 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4776 : *
4777 : * Once all processing for the created session is complete, or if no further
4778 : * refinement of the request is required, the GDALAsyncReader object should
4779 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4780 : *
4781 : * Note that the data buffer (pData) will potentially continue to be
4782 : * updated as long as the session lives, but it is not deallocated when
4783 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4784 : * should be deallocated by the application at that point.
4785 : *
4786 : * Additional information on asynchronous IO in GDAL may be found at:
4787 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4788 : *
4789 : * This method is the same as the C GDALBeginAsyncReader() function.
4790 : *
4791 : * @param nXOff The pixel offset to the top left corner of the region
4792 : * of the band to be accessed. This would be zero to start from the left side.
4793 : *
4794 : * @param nYOff The line offset to the top left corner of the region
4795 : * of the band to be accessed. This would be zero to start from the top.
4796 : *
4797 : * @param nXSize The width of the region of the band to be accessed in pixels.
4798 : *
4799 : * @param nYSize The height of the region of the band to be accessed in lines.
4800 : *
4801 : * @param pBuf The buffer into which the data should be read. This buffer must
4802 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4803 : * It is organized in left to right,top to bottom pixel order. Spacing is
4804 : * controlled by the nPixelSpace, and nLineSpace parameters.
4805 : *
4806 : * @param nBufXSize the width of the buffer image into which the desired region
4807 : * is to be read, or from which it is to be written.
4808 : *
4809 : * @param nBufYSize the height of the buffer image into which the desired
4810 : * region is to be read, or from which it is to be written.
4811 : *
4812 : * @param eBufType the type of the pixel values in the pData data buffer. The
4813 : * pixel values will automatically be translated to/from the GDALRasterBand
4814 : * data type as needed.
4815 : *
4816 : * @param nBandCount the number of bands being read or written.
4817 : *
4818 : * @param panBandMap the list of nBandCount band numbers being read/written.
4819 : * Note band numbers are 1 based. This may be NULL to select the first
4820 : * nBandCount bands.
4821 : *
4822 : * @param nPixelSpace The byte offset from the start of one pixel value in
4823 : * pData to the start of the next pixel value within a scanline. If defaulted
4824 : * (0) the size of the datatype eBufType is used.
4825 : *
4826 : * @param nLineSpace The byte offset from the start of one scanline in
4827 : * pData to the start of the next. If defaulted the size of the datatype
4828 : * eBufType * nBufXSize is used.
4829 : *
4830 : * @param nBandSpace the byte offset from the start of one bands data to the
4831 : * start of the next. If defaulted (zero) the value will be
4832 : * nLineSpace * nBufYSize implying band sequential organization
4833 : * of the data buffer.
4834 : *
4835 : * @param papszOptions Driver specific control options in a string list or NULL.
4836 : * Consult driver documentation for options supported.
4837 : *
4838 : * @return The GDALAsyncReader object representing the request.
4839 : */
4840 :
4841 1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
4842 : int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4843 : int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4844 : int nPixelSpace, int nLineSpace, int nBandSpace, char **papszOptions)
4845 : {
4846 : // See gdaldefaultasync.cpp
4847 :
4848 1 : return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4849 : nBufXSize, nBufYSize, eBufType, nBandCount,
4850 : panBandMap, nPixelSpace, nLineSpace,
4851 1 : nBandSpace, papszOptions);
4852 : }
4853 :
4854 : /************************************************************************/
4855 : /* GDALBeginAsyncReader() */
4856 : /************************************************************************/
4857 :
4858 : /**
4859 : * \brief Sets up an asynchronous data request
4860 : *
4861 : * This method establish an asynchronous raster read request for the
4862 : * indicated window on the dataset into the indicated buffer. The parameters
4863 : * for windowing, buffer size, buffer type and buffer organization are similar
4864 : * to those for GDALDataset::RasterIO(); however, this call only launches
4865 : * the request and filling the buffer is accomplished via calls to
4866 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4867 : *
4868 : * Once all processing for the created session is complete, or if no further
4869 : * refinement of the request is required, the GDALAsyncReader object should
4870 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4871 : *
4872 : * Note that the data buffer (pData) will potentially continue to be
4873 : * updated as long as the session lives, but it is not deallocated when
4874 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4875 : * should be deallocated by the application at that point.
4876 : *
4877 : * Additional information on asynchronous IO in GDAL may be found at:
4878 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4879 : *
4880 : * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4881 : *
4882 : * @param hDS handle to the dataset object.
4883 : *
4884 : * @param nXOff The pixel offset to the top left corner of the region
4885 : * of the band to be accessed. This would be zero to start from the left side.
4886 : *
4887 : * @param nYOff The line offset to the top left corner of the region
4888 : * of the band to be accessed. This would be zero to start from the top.
4889 : *
4890 : * @param nXSize The width of the region of the band to be accessed in pixels.
4891 : *
4892 : * @param nYSize The height of the region of the band to be accessed in lines.
4893 : *
4894 : * @param pBuf The buffer into which the data should be read. This buffer must
4895 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4896 : * It is organized in left to right,top to bottom pixel order. Spacing is
4897 : * controlled by the nPixelSpace, and nLineSpace parameters.
4898 : *
4899 : * @param nBufXSize the width of the buffer image into which the desired region
4900 : * is to be read, or from which it is to be written.
4901 : *
4902 : * @param nBufYSize the height of the buffer image into which the desired
4903 : * region is to be read, or from which it is to be written.
4904 : *
4905 : * @param eBufType the type of the pixel values in the pData data buffer. The
4906 : * pixel values will automatically be translated to/from the GDALRasterBand
4907 : * data type as needed.
4908 : *
4909 : * @param nBandCount the number of bands being read or written.
4910 : *
4911 : * @param panBandMap the list of nBandCount band numbers being read/written.
4912 : * Note band numbers are 1 based. This may be NULL to select the first
4913 : * nBandCount bands.
4914 : *
4915 : * @param nPixelSpace The byte offset from the start of one pixel value in
4916 : * pData to the start of the next pixel value within a scanline. If defaulted
4917 : * (0) the size of the datatype eBufType is used.
4918 : *
4919 : * @param nLineSpace The byte offset from the start of one scanline in
4920 : * pData to the start of the next. If defaulted the size of the datatype
4921 : * eBufType * nBufXSize is used.
4922 : *
4923 : * @param nBandSpace the byte offset from the start of one bands data to the
4924 : * start of the next. If defaulted (zero) the value will be
4925 : * nLineSpace * nBufYSize implying band sequential organization
4926 : * of the data buffer.
4927 : *
4928 : * @param papszOptions Driver specific control options in a string list or NULL.
4929 : * Consult driver documentation for options supported.
4930 : *
4931 : * @return handle representing the request.
4932 : */
4933 :
4934 2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
4935 : GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
4936 : int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
4937 : int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
4938 : CSLConstList papszOptions)
4939 :
4940 : {
4941 2 : VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
4942 : return static_cast<GDALAsyncReaderH>(
4943 2 : GDALDataset::FromHandle(hDS)->BeginAsyncReader(
4944 : nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
4945 : nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
4946 2 : const_cast<char **>(papszOptions)));
4947 : }
4948 :
4949 : /************************************************************************/
4950 : /* EndAsyncReader() */
4951 : /************************************************************************/
4952 :
4953 : /**
4954 : * End asynchronous request.
4955 : *
4956 : * This method destroys an asynchronous io request and recovers all
4957 : * resources associated with it.
4958 : *
4959 : * This method is the same as the C function GDALEndAsyncReader().
4960 : *
4961 : * @param poARIO pointer to a GDALAsyncReader
4962 : */
4963 :
4964 1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
4965 : {
4966 1 : delete poARIO;
4967 1 : }
4968 :
4969 : /************************************************************************/
4970 : /* GDALEndAsyncReader() */
4971 : /************************************************************************/
4972 :
4973 : /**
4974 : * End asynchronous request.
4975 : *
4976 : * This method destroys an asynchronous io request and recovers all
4977 : * resources associated with it.
4978 : *
4979 : * This method is the same as the C++ method GDALDataset::EndAsyncReader().
4980 : *
4981 : * @param hDS handle to the dataset object.
4982 : * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
4983 : */
4984 :
4985 1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
4986 : GDALAsyncReaderH hAsyncReaderH)
4987 : {
4988 1 : VALIDATE_POINTER0(hDS, "GDALDataset");
4989 1 : VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
4990 1 : GDALDataset::FromHandle(hDS)->EndAsyncReader(
4991 1 : static_cast<GDALAsyncReader *>(hAsyncReaderH));
4992 : }
4993 :
4994 : /************************************************************************/
4995 : /* CloseDependentDatasets() */
4996 : /************************************************************************/
4997 :
4998 : /**
4999 : * Drop references to any other datasets referenced by this dataset.
5000 : *
5001 : * This method should release any reference to other datasets (e.g. a VRT
5002 : * dataset to its sources), but not close the current dataset itself.
5003 : *
5004 : * If at least, one reference to a dependent dataset has been dropped,
5005 : * this method should return TRUE. Otherwise it *should* return FALSE.
5006 : * (Failure to return the proper value might result in infinite loop)
5007 : *
5008 : * This method can be called several times on a given dataset. After
5009 : * the first time, it should not do anything and return FALSE.
5010 : *
5011 : * The driver implementation may choose to destroy its raster bands,
5012 : * so be careful not to call any method on the raster bands afterwards.
5013 : *
5014 : * Basically the only safe action you can do after calling
5015 : * CloseDependentDatasets() is to call the destructor.
5016 : *
5017 : * Note: the only legitimate caller of CloseDependentDatasets() is
5018 : * GDALDriverManager::~GDALDriverManager()
5019 : *
5020 : * @return TRUE if at least one reference to another dataset has been dropped.
5021 : */
5022 18793 : int GDALDataset::CloseDependentDatasets()
5023 : {
5024 18793 : return oOvManager.CloseDependentDatasets();
5025 : }
5026 :
5027 : /************************************************************************/
5028 : /* ReportError() */
5029 : /************************************************************************/
5030 :
5031 : #ifndef DOXYGEN_XML
5032 : /**
5033 : * \brief Emits an error related to a dataset.
5034 : *
5035 : * This function is a wrapper for regular CPLError(). The only difference
5036 : * with CPLError() is that it prepends the error message with the dataset
5037 : * name.
5038 : *
5039 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5040 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5041 : * @param fmt a printf() style format string. Any additional arguments
5042 : * will be treated as arguments to fill in this format in a manner
5043 : * similar to printf().
5044 : *
5045 : */
5046 :
5047 102 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5048 : const char *fmt, ...) const
5049 : {
5050 : va_list args;
5051 102 : va_start(args, fmt);
5052 102 : ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5053 102 : va_end(args);
5054 102 : }
5055 :
5056 : /**
5057 : * \brief Emits an error related to a dataset (static method)
5058 : *
5059 : * This function is a wrapper for regular CPLError(). The only difference
5060 : * with CPLError() is that it prepends the error message with the dataset
5061 : * name.
5062 : *
5063 : * @param pszDSName dataset name.
5064 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5065 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5066 : * @param fmt a printf() style format string. Any additional arguments
5067 : * will be treated as arguments to fill in this format in a manner
5068 : * similar to printf().
5069 : *
5070 : * @since GDAL 3.2.0
5071 : */
5072 :
5073 124 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5074 : CPLErrorNum err_no, const char *fmt, ...)
5075 : {
5076 : va_list args;
5077 124 : va_start(args, fmt);
5078 124 : ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5079 124 : va_end(args);
5080 124 : }
5081 :
5082 226 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5083 : CPLErrorNum err_no, const char *fmt,
5084 : va_list args)
5085 : {
5086 226 : pszDSName = CPLGetFilename(pszDSName);
5087 226 : if (pszDSName[0] != '\0')
5088 : {
5089 209 : CPLError(eErrClass, err_no, "%s",
5090 418 : std::string(pszDSName)
5091 209 : .append(": ")
5092 418 : .append(CPLString().vPrintf(fmt, args))
5093 : .c_str());
5094 : }
5095 : else
5096 : {
5097 17 : CPLErrorV(eErrClass, err_no, fmt, args);
5098 : }
5099 226 : }
5100 : #endif
5101 :
5102 : /************************************************************************/
5103 : /* GetMetadata() */
5104 : /************************************************************************/
5105 71915 : char **GDALDataset::GetMetadata(const char *pszDomain)
5106 : {
5107 : #ifndef WITHOUT_DERIVED
5108 71915 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5109 : {
5110 10 : oDerivedMetadataList.Clear();
5111 :
5112 : // First condition: at least one raster band.
5113 10 : if (GetRasterCount() > 0)
5114 : {
5115 : // Check if there is at least one complex band.
5116 10 : bool hasAComplexBand = false;
5117 :
5118 19 : for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5119 : {
5120 11 : if (GDALDataTypeIsComplex(
5121 11 : GetRasterBand(rasterId)->GetRasterDataType()))
5122 : {
5123 2 : hasAComplexBand = true;
5124 2 : break;
5125 : }
5126 : }
5127 :
5128 10 : unsigned int nbSupportedDerivedDS = 0;
5129 : const DerivedDatasetDescription *poDDSDesc =
5130 10 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5131 :
5132 10 : int nNumDataset = 1;
5133 80 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5134 : ++derivedId)
5135 : {
5136 126 : if (hasAComplexBand ||
5137 126 : CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5138 : "complex")
5139 : {
5140 : oDerivedMetadataList.SetNameValue(
5141 : CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5142 : CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5143 22 : poDDSDesc[derivedId].pszDatasetName,
5144 22 : GetDescription()));
5145 :
5146 : CPLString osDesc(
5147 : CPLSPrintf("%s from %s",
5148 22 : poDDSDesc[derivedId].pszDatasetDescription,
5149 22 : GetDescription()));
5150 : oDerivedMetadataList.SetNameValue(
5151 : CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5152 22 : osDesc.c_str());
5153 :
5154 22 : nNumDataset++;
5155 : }
5156 : }
5157 : }
5158 10 : return oDerivedMetadataList.List();
5159 : }
5160 : #endif
5161 :
5162 71905 : return GDALMajorObject::GetMetadata(pszDomain);
5163 : }
5164 :
5165 : // clang-format off
5166 :
5167 : /**
5168 : * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5169 : * \brief Set metadata.
5170 : *
5171 : * CAUTION: depending on the format, older values of the updated information
5172 : * might still be found in the file in a "ghost" state, even if no longer
5173 : * accessible through the GDAL API. This is for example the case of the GTiff
5174 : * format (this is not a exhaustive list)
5175 : *
5176 : * The C function GDALSetMetadata() does the same thing as this method.
5177 : *
5178 : * @param papszMetadata the metadata in name=value string list format to
5179 : * apply.
5180 : * @param pszDomain the domain of interest. Use "" or NULL for the default
5181 : * domain.
5182 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5183 : * metadata has been accepted, but is likely not maintained persistently
5184 : * by the underlying object between sessions.
5185 : */
5186 :
5187 : /**
5188 : * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5189 : * \brief Set single metadata item.
5190 : *
5191 : * CAUTION: depending on the format, older values of the updated information
5192 : * might still be found in the file in a "ghost" state, even if no longer
5193 : * accessible through the GDAL API. This is for example the case of the GTiff
5194 : * format (this is not a exhaustive list)
5195 : *
5196 : * The C function GDALSetMetadataItem() does the same thing as this method.
5197 : *
5198 : * @param pszName the key for the metadata item to fetch.
5199 : * @param pszValue the value to assign to the key.
5200 : * @param pszDomain the domain to set within, use NULL for the default domain.
5201 : *
5202 : * @return CE_None on success, or an error code on failure.
5203 : */
5204 :
5205 : // clang-format on
5206 :
5207 : /************************************************************************/
5208 : /* GetMetadataDomainList() */
5209 : /************************************************************************/
5210 :
5211 1045 : char **GDALDataset::GetMetadataDomainList()
5212 : {
5213 1045 : char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5214 :
5215 : // Ensure that we do not duplicate DERIVED domain.
5216 1188 : if (GetRasterCount() > 0 &&
5217 143 : CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5218 : {
5219 : currentDomainList =
5220 143 : CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5221 : }
5222 1045 : return currentDomainList;
5223 : }
5224 :
5225 : /************************************************************************/
5226 : /* GetDriverName() */
5227 : /************************************************************************/
5228 :
5229 : /** Return driver name.
5230 : * @return driver name.
5231 : */
5232 2065 : const char *GDALDataset::GetDriverName() const
5233 : {
5234 2065 : if (poDriver)
5235 2053 : return poDriver->GetDescription();
5236 12 : return "";
5237 : }
5238 :
5239 : /************************************************************************/
5240 : /* GDALDatasetReleaseResultSet() */
5241 : /************************************************************************/
5242 :
5243 : /**
5244 : \brief Release results of ExecuteSQL().
5245 :
5246 : This function should only be used to deallocate OGRLayers resulting from
5247 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
5248 : results set before destroying the GDALDataset may cause errors.
5249 :
5250 : This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5251 :
5252 :
5253 : @param hDS the dataset handle.
5254 : @param hLayer the result of a previous ExecuteSQL() call.
5255 :
5256 : */
5257 3501 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5258 :
5259 : {
5260 3501 : VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5261 :
5262 : #ifdef OGRAPISPY_ENABLED
5263 3501 : if (bOGRAPISpyEnabled)
5264 6 : OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5265 : #endif
5266 :
5267 7002 : GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5268 3501 : OGRLayer::FromHandle(hLayer));
5269 : }
5270 :
5271 : /************************************************************************/
5272 : /* GDALDatasetGetLayerCount() */
5273 : /************************************************************************/
5274 :
5275 : /**
5276 : \brief Get the number of layers in this dataset.
5277 :
5278 : This function is the same as the C++ method GDALDataset::GetLayerCount()
5279 :
5280 :
5281 : @param hDS the dataset handle.
5282 : @return layer count.
5283 : */
5284 :
5285 1481 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5286 :
5287 : {
5288 1481 : VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5289 :
5290 : #ifdef OGRAPISPY_ENABLED
5291 1481 : if (bOGRAPISpyEnabled)
5292 2 : OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5293 : #endif
5294 :
5295 1481 : return GDALDataset::FromHandle(hDS)->GetLayerCount();
5296 : }
5297 :
5298 : /************************************************************************/
5299 : /* GDALDatasetGetLayer() */
5300 : /************************************************************************/
5301 :
5302 : /**
5303 : \brief Fetch a layer by index.
5304 :
5305 : The returned layer remains owned by the
5306 : GDALDataset and should not be deleted by the application.
5307 :
5308 : This function is the same as the C++ method GDALDataset::GetLayer()
5309 :
5310 :
5311 : @param hDS the dataset handle.
5312 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5313 :
5314 : @return the layer, or NULL if iLayer is out of range or an error occurs.
5315 : */
5316 :
5317 9892 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5318 :
5319 : {
5320 9892 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5321 :
5322 : OGRLayerH hLayer =
5323 9892 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5324 :
5325 : #ifdef OGRAPISPY_ENABLED
5326 9892 : if (bOGRAPISpyEnabled)
5327 3 : OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5328 : #endif
5329 :
5330 9892 : return hLayer;
5331 : }
5332 :
5333 : /************************************************************************/
5334 : /* GDALDatasetGetLayerByName() */
5335 : /************************************************************************/
5336 :
5337 : /**
5338 : \brief Fetch a layer by name.
5339 :
5340 : The returned layer remains owned by the
5341 : GDALDataset and should not be deleted by the application.
5342 :
5343 : This function is the same as the C++ method GDALDataset::GetLayerByName()
5344 :
5345 :
5346 : @param hDS the dataset handle.
5347 : @param pszName the layer name of the layer to fetch.
5348 :
5349 : @return the layer, or NULL if Layer is not found or an error occurs.
5350 : */
5351 :
5352 3413 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5353 :
5354 : {
5355 3413 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5356 :
5357 3413 : OGRLayerH hLayer = OGRLayer::ToHandle(
5358 3413 : GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5359 :
5360 : #ifdef OGRAPISPY_ENABLED
5361 3413 : if (bOGRAPISpyEnabled)
5362 4 : OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5363 : #endif
5364 :
5365 3413 : return hLayer;
5366 : }
5367 :
5368 : /************************************************************************/
5369 : /* GDALDatasetIsLayerPrivate() */
5370 : /************************************************************************/
5371 :
5372 : /**
5373 : \brief Returns true if the layer at the specified index is deemed a private or
5374 : system table, or an internal detail only.
5375 :
5376 : This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5377 :
5378 : @since GDAL 3.4
5379 :
5380 : @param hDS the dataset handle.
5381 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5382 :
5383 : @return true if the layer is a private or system table.
5384 : */
5385 :
5386 91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5387 :
5388 : {
5389 91 : VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5390 :
5391 91 : const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5392 :
5393 91 : return res ? 1 : 0;
5394 : }
5395 :
5396 : /************************************************************************/
5397 : /* GetLayerIndex() */
5398 : /************************************************************************/
5399 :
5400 : /**
5401 : \brief Returns the index of the layer specified by name.
5402 :
5403 : @since GDAL 3.12
5404 :
5405 : @param pszName layer name (not NULL)
5406 :
5407 : @return an index >= 0, or -1 if not found.
5408 : */
5409 :
5410 3 : int GDALDataset::GetLayerIndex(const char *pszName) const
5411 : {
5412 3 : const int nLayerCount = GetLayerCount();
5413 3 : int iMatch = -1;
5414 6 : for (int i = 0; i < nLayerCount; ++i)
5415 : {
5416 5 : if (const auto poLayer = GetLayer(i))
5417 : {
5418 5 : const char *pszLayerName = poLayer->GetDescription();
5419 5 : if (strcmp(pszName, pszLayerName) == 0)
5420 : {
5421 2 : iMatch = i;
5422 2 : break;
5423 : }
5424 3 : else if (EQUAL(pszName, pszLayerName))
5425 : {
5426 0 : iMatch = i;
5427 : }
5428 : }
5429 : }
5430 3 : return iMatch;
5431 : }
5432 :
5433 : /************************************************************************/
5434 : /* GDALDatasetDeleteLayer() */
5435 : /************************************************************************/
5436 :
5437 : /**
5438 : \brief Delete the indicated layer from the datasource.
5439 :
5440 : If this function is supported
5441 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5442 :
5443 : This method is the same as the C++ method GDALDataset::DeleteLayer().
5444 :
5445 :
5446 : @param hDS the dataset handle.
5447 : @param iLayer the index of the layer to delete.
5448 :
5449 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5450 : layers is not supported for this datasource.
5451 :
5452 : */
5453 41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5454 :
5455 : {
5456 41 : VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5457 :
5458 : #ifdef OGRAPISPY_ENABLED
5459 41 : if (bOGRAPISpyEnabled)
5460 2 : OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5461 : #endif
5462 :
5463 41 : return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5464 : }
5465 :
5466 : /************************************************************************/
5467 : /* CreateLayer() */
5468 : /************************************************************************/
5469 :
5470 : /**
5471 : \brief This method attempts to create a new layer on the dataset with the
5472 : indicated name, coordinate system, geometry type.
5473 :
5474 : The papszOptions argument
5475 : can be used to control driver specific creation options. These options are
5476 : normally documented in the format specific documentation.
5477 : That function will try to validate the creation option list passed to the
5478 : driver with the GDALValidateCreationOptions() method. This check can be
5479 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5480 : to NO.
5481 :
5482 : Drivers should extend the ICreateLayer() method and not
5483 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5484 : delegating the actual work to ICreateLayer().
5485 :
5486 : This method is the same as the C function GDALDatasetCreateLayer() and the
5487 : deprecated OGR_DS_CreateLayer().
5488 :
5489 : Example:
5490 :
5491 : \code{.cpp}
5492 : #include "gdal.h"
5493 : #include "cpl_string.h"
5494 :
5495 : ...
5496 :
5497 : OGRLayer *poLayer;
5498 : char **papszOptions;
5499 :
5500 : if( !poDS->TestCapability( ODsCCreateLayer ) )
5501 : {
5502 : ...
5503 : }
5504 :
5505 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5506 : poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5507 : papszOptions );
5508 : CSLDestroy( papszOptions );
5509 :
5510 : if( poLayer == NULL )
5511 : {
5512 : ...
5513 : }
5514 : \endcode
5515 :
5516 : @param pszName the name for the new layer. This should ideally not
5517 : match any existing layer on the datasource.
5518 : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
5519 : no coordinate system is available.
5520 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5521 : are no constraints on the types geometry to be written.
5522 : @param papszOptions a StringList of name=value options. Options are driver
5523 : specific.
5524 :
5525 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5526 :
5527 : */
5528 :
5529 8249 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5530 : const OGRSpatialReference *poSpatialRef,
5531 : OGRwkbGeometryType eGType,
5532 : CSLConstList papszOptions)
5533 :
5534 : {
5535 8249 : if (eGType == wkbNone)
5536 : {
5537 519 : return CreateLayer(pszName, nullptr, papszOptions);
5538 : }
5539 : else
5540 : {
5541 15460 : OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5542 7730 : oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5543 7730 : return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5544 : }
5545 : }
5546 :
5547 : /**
5548 : \brief This method attempts to create a new layer on the dataset with the
5549 : indicated name and geometry field definition.
5550 :
5551 : When poGeomFieldDefn is not null, most drivers should honor
5552 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5553 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5554 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5555 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5556 : very few currently.
5557 :
5558 : Note that even if a geometry coordinate precision is set and a driver honors the
5559 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5560 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5561 : with the coordinate precision. That is they are assumed to be valid once their
5562 : coordinates are rounded to it. If it might not be the case, the user may set
5563 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5564 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5565 : the passed geometries.
5566 :
5567 : The papszOptions argument
5568 : can be used to control driver specific creation options. These options are
5569 : normally documented in the format specific documentation.
5570 : This function will try to validate the creation option list passed to the
5571 : driver with the GDALValidateCreationOptions() method. This check can be
5572 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5573 : to NO.
5574 :
5575 : Drivers should extend the ICreateLayer() method and not
5576 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5577 : delegating the actual work to ICreateLayer().
5578 :
5579 : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5580 :
5581 : @param pszName the name for the new layer. This should ideally not
5582 : match any existing layer on the datasource.
5583 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
5584 : or NULL if there is no geometry field.
5585 : @param papszOptions a StringList of name=value options. Options are driver
5586 : specific.
5587 :
5588 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5589 : @since 3.9
5590 :
5591 : */
5592 :
5593 9624 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5594 : const OGRGeomFieldDefn *poGeomFieldDefn,
5595 : CSLConstList papszOptions)
5596 :
5597 : {
5598 9624 : if (CPLTestBool(
5599 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5600 : {
5601 9624 : ValidateLayerCreationOptions(papszOptions);
5602 : }
5603 :
5604 : OGRLayer *poLayer;
5605 9624 : if (poGeomFieldDefn)
5606 : {
5607 8696 : OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5608 8790 : if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5609 94 : !TestCapability(ODsCCurveGeometries))
5610 : {
5611 23 : oGeomFieldDefn.SetType(
5612 : OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5613 : }
5614 :
5615 8696 : poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5616 : }
5617 : else
5618 : {
5619 928 : poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5620 : }
5621 : #ifdef DEBUG
5622 9695 : if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5623 71 : !poLayer->TestCapability(OLCCurveGeometries))
5624 : {
5625 0 : CPLError(CE_Warning, CPLE_AppDefined,
5626 : "Inconsistent driver: Layer geometry type is non-linear, but "
5627 : "TestCapability(OLCCurveGeometries) returns FALSE.");
5628 : }
5629 : #endif
5630 :
5631 9624 : return poLayer;
5632 : }
5633 :
5634 : //! @cond Doxygen_Suppress
5635 :
5636 : // Technical override to avoid ambiguous choice between the old and new
5637 : // new CreateLayer() signatures.
5638 12 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5639 : {
5640 24 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5641 24 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5642 : }
5643 :
5644 : // Technical override to avoid ambiguous choice between the old and new
5645 : // new CreateLayer() signatures.
5646 1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5647 : {
5648 2 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5649 2 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5650 : }
5651 :
5652 : //!@endcond
5653 :
5654 : /************************************************************************/
5655 : /* GDALDatasetCreateLayer() */
5656 : /************************************************************************/
5657 :
5658 : /**
5659 : \brief This function attempts to create a new layer on the dataset with the
5660 : indicated name, coordinate system, geometry type.
5661 :
5662 : The papszOptions argument can be used to control driver specific creation
5663 : options. These options are normally documented in the format specific
5664 : documentation.
5665 :
5666 : This method is the same as the C++ method GDALDataset::CreateLayer().
5667 :
5668 : Example:
5669 :
5670 : \code{.c}
5671 : #include "gdal.h"
5672 : #include "cpl_string.h"
5673 :
5674 : ...
5675 :
5676 : OGRLayerH hLayer;
5677 : char **papszOptions;
5678 :
5679 : if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5680 : {
5681 : ...
5682 : }
5683 :
5684 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5685 : hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5686 : papszOptions );
5687 : CSLDestroy( papszOptions );
5688 :
5689 : if( hLayer == NULL )
5690 : {
5691 : ...
5692 : }
5693 : \endcode
5694 :
5695 :
5696 : @param hDS the dataset handle
5697 : @param pszName the name for the new layer. This should ideally not
5698 : match any existing layer on the datasource.
5699 : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
5700 : no coordinate system is available.
5701 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5702 : are no constraints on the types geometry to be written.
5703 : @param papszOptions a StringList of name=value options. Options are driver
5704 : specific.
5705 :
5706 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5707 :
5708 : */
5709 :
5710 6400 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5711 : OGRSpatialReferenceH hSpatialRef,
5712 : OGRwkbGeometryType eGType,
5713 : CSLConstList papszOptions)
5714 :
5715 : {
5716 6400 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5717 :
5718 6400 : if (pszName == nullptr)
5719 : {
5720 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5721 : "Name was NULL in GDALDatasetCreateLayer");
5722 0 : return nullptr;
5723 : }
5724 :
5725 : OGRLayerH hLayer =
5726 12800 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5727 6400 : pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5728 : const_cast<char **>(papszOptions)));
5729 :
5730 : #ifdef OGRAPISPY_ENABLED
5731 6400 : if (bOGRAPISpyEnabled)
5732 8 : OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5733 : const_cast<char **>(papszOptions), hLayer);
5734 : #endif
5735 :
5736 6400 : return hLayer;
5737 : }
5738 :
5739 : /************************************************************************/
5740 : /* GDALDatasetCreateLayerFromGeomFieldDefn() */
5741 : /************************************************************************/
5742 :
5743 : /**
5744 : \brief This function attempts to create a new layer on the dataset with the
5745 : indicated name and geometry field.
5746 :
5747 : When poGeomFieldDefn is not null, most drivers should honor
5748 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5749 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5750 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5751 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5752 : very few currently.
5753 :
5754 : Note that even if a geometry coordinate precision is set and a driver honors the
5755 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5756 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5757 : with the coordinate precision. That is they are assumed to be valid once their
5758 : coordinates are rounded to it. If it might not be the case, the user may set
5759 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5760 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5761 : the passed geometries.
5762 :
5763 : The papszOptions argument can be used to control driver specific creation
5764 : options. These options are normally documented in the format specific
5765 : documentation.
5766 :
5767 : This method is the same as the C++ method GDALDataset::CreateLayer().
5768 :
5769 : @param hDS the dataset handle
5770 : @param pszName the name for the new layer. This should ideally not
5771 : match any existing layer on the datasource.
5772 : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5773 : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5774 : for drivers supporting that interface).
5775 : @param papszOptions a StringList of name=value options. Options are driver
5776 : specific.
5777 :
5778 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5779 :
5780 : @since GDAL 3.9
5781 :
5782 : */
5783 :
5784 : OGRLayerH
5785 14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5786 : OGRGeomFieldDefnH hGeomFieldDefn,
5787 : CSLConstList papszOptions)
5788 :
5789 : {
5790 14 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5791 :
5792 14 : if (!pszName)
5793 : {
5794 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5795 : "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5796 0 : return nullptr;
5797 : }
5798 :
5799 : OGRLayerH hLayer =
5800 28 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5801 14 : pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5802 : papszOptions));
5803 14 : return hLayer;
5804 : }
5805 :
5806 : /************************************************************************/
5807 : /* GDALDatasetCopyLayer() */
5808 : /************************************************************************/
5809 :
5810 : /**
5811 : \brief Duplicate an existing layer.
5812 :
5813 : This function creates a new layer, duplicate the field definitions of the
5814 : source layer and then duplicate each features of the source layer.
5815 : The papszOptions argument
5816 : can be used to control driver specific creation options. These options are
5817 : normally documented in the format specific documentation.
5818 : The source layer may come from another dataset.
5819 :
5820 : This method is the same as the C++ method GDALDataset::CopyLayer()
5821 :
5822 :
5823 : @param hDS the dataset handle.
5824 : @param hSrcLayer source layer.
5825 : @param pszNewName the name of the layer to create.
5826 : @param papszOptions a StringList of name=value options. Options are driver
5827 : specific.
5828 :
5829 : @return a handle to the layer, or NULL if an error occurs.
5830 : */
5831 20 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5832 : const char *pszNewName,
5833 : CSLConstList papszOptions)
5834 :
5835 : {
5836 20 : VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5837 20 : VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5838 20 : VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5839 :
5840 40 : return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5841 : OGRLayer::FromHandle(hSrcLayer), pszNewName,
5842 40 : const_cast<char **>(papszOptions)));
5843 : }
5844 :
5845 : /************************************************************************/
5846 : /* GDALDatasetExecuteSQL() */
5847 : /************************************************************************/
5848 :
5849 : /**
5850 : \brief Execute an SQL statement against the data store.
5851 :
5852 : The result of an SQL query is either NULL for statements that are in error,
5853 : or that have no results set, or an OGRLayer pointer representing a results
5854 : set from the query. Note that this OGRLayer is in addition to the layers
5855 : in the data store and must be destroyed with
5856 : ReleaseResultSet() before the dataset is closed
5857 : (destroyed).
5858 :
5859 : This method is the same as the C++ method GDALDataset::ExecuteSQL()
5860 :
5861 : For more information on the SQL dialect supported internally by OGR
5862 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5863 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5864 : to the underlying RDBMS.
5865 :
5866 : Starting with OGR 1.10, the <a
5867 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5868 : also be used.
5869 :
5870 :
5871 : @param hDS the dataset handle.
5872 : @param pszStatement the SQL statement to execute.
5873 : @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5874 :
5875 : @param pszDialect allows control of the statement dialect. If set to NULL, the
5876 : OGR SQL engine will be used, except for RDBMS drivers that will use their
5877 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
5878 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5879 :
5880 : @return an OGRLayer containing the results of the query. Deallocate with
5881 : GDALDatasetReleaseResultSet().
5882 :
5883 : */
5884 :
5885 10544 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5886 : OGRGeometryH hSpatialFilter,
5887 : const char *pszDialect)
5888 :
5889 : {
5890 10544 : VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
5891 :
5892 : OGRLayerH hLayer =
5893 21088 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
5894 10544 : pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
5895 :
5896 : #ifdef OGRAPISPY_ENABLED
5897 10544 : if (bOGRAPISpyEnabled)
5898 4 : OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
5899 : hLayer);
5900 : #endif
5901 :
5902 10544 : return hLayer;
5903 : }
5904 :
5905 : /************************************************************************/
5906 : /* GDALDatasetAbortSQL() */
5907 : /************************************************************************/
5908 :
5909 : /**
5910 : \brief Abort any SQL statement running in the data store.
5911 :
5912 : This function can be safely called from any thread (pending that the dataset
5913 : object is still alive). Driver implementations will make sure that it can be
5914 : called in a thread-safe way.
5915 :
5916 : This might not be implemented by all drivers. At time of writing, only SQLite,
5917 : GPKG and PG drivers implement it
5918 :
5919 : This method is the same as the C++ method GDALDataset::AbortSQL()
5920 :
5921 : @since GDAL 3.2.0
5922 :
5923 : @param hDS the dataset handle.
5924 :
5925 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
5926 : is not supported for this datasource. .
5927 :
5928 : */
5929 :
5930 6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
5931 :
5932 : {
5933 6 : VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
5934 6 : return GDALDataset::FromHandle(hDS)->AbortSQL();
5935 : }
5936 :
5937 : /************************************************************************/
5938 : /* GDALDatasetGetStyleTable() */
5939 : /************************************************************************/
5940 :
5941 : /**
5942 : \brief Returns dataset style table.
5943 :
5944 : This function is the same as the C++ method GDALDataset::GetStyleTable()
5945 :
5946 :
5947 : @param hDS the dataset handle
5948 : @return handle to a style table which should not be modified or freed by the
5949 : caller.
5950 : */
5951 :
5952 6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
5953 :
5954 : {
5955 6 : VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
5956 :
5957 : return reinterpret_cast<OGRStyleTableH>(
5958 6 : GDALDataset::FromHandle(hDS)->GetStyleTable());
5959 : }
5960 :
5961 : /************************************************************************/
5962 : /* GDALDatasetSetStyleTableDirectly() */
5963 : /************************************************************************/
5964 :
5965 : /**
5966 : \brief Set dataset style table.
5967 :
5968 : This function operate exactly as GDALDatasetSetStyleTable() except that it
5969 : assumes ownership of the passed table.
5970 :
5971 : This function is the same as the C++ method
5972 : GDALDataset::SetStyleTableDirectly()
5973 :
5974 :
5975 : @param hDS the dataset handle
5976 : @param hStyleTable style table handle to set
5977 :
5978 : */
5979 :
5980 0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
5981 : OGRStyleTableH hStyleTable)
5982 :
5983 : {
5984 0 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
5985 :
5986 0 : GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
5987 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
5988 : }
5989 :
5990 : /************************************************************************/
5991 : /* GDALDatasetSetStyleTable() */
5992 : /************************************************************************/
5993 :
5994 : /**
5995 : \brief Set dataset style table.
5996 :
5997 : This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
5998 : it assumes ownership of the passed table.
5999 :
6000 : This function is the same as the C++ method GDALDataset::SetStyleTable()
6001 :
6002 :
6003 : @param hDS the dataset handle
6004 : @param hStyleTable style table handle to set
6005 :
6006 : */
6007 :
6008 5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6009 :
6010 : {
6011 5 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6012 5 : VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6013 :
6014 5 : GDALDataset::FromHandle(hDS)->SetStyleTable(
6015 5 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6016 : }
6017 :
6018 : /************************************************************************/
6019 : /* ValidateLayerCreationOptions() */
6020 : /************************************************************************/
6021 :
6022 : //! @cond Doxygen_Suppress
6023 9624 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6024 : {
6025 : const char *pszOptionList =
6026 9624 : GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6027 9624 : if (pszOptionList == nullptr && poDriver != nullptr)
6028 : {
6029 : pszOptionList =
6030 9583 : poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6031 : }
6032 19248 : CPLString osDataset;
6033 9624 : osDataset.Printf("dataset %s", GetDescription());
6034 9624 : return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
6035 19248 : osDataset);
6036 : }
6037 :
6038 : //! @endcond
6039 :
6040 : /************************************************************************/
6041 : /* Release() */
6042 : /************************************************************************/
6043 :
6044 : /**
6045 : \brief Drop a reference to this dataset, and if the reference count drops to one
6046 : close (destroy) the dataset.
6047 :
6048 : This method is the same as the C function OGRReleaseDataSource().
6049 :
6050 : @deprecated. Use GDALClose() instead
6051 :
6052 : @return OGRERR_NONE on success or an error code.
6053 : */
6054 :
6055 4333 : OGRErr GDALDataset::Release()
6056 :
6057 : {
6058 4333 : ReleaseRef();
6059 4333 : return OGRERR_NONE;
6060 : }
6061 :
6062 : /************************************************************************/
6063 : /* GetRefCount() */
6064 : /************************************************************************/
6065 :
6066 : /**
6067 : \brief Fetch reference count.
6068 :
6069 : This method is the same as the C function OGR_DS_GetRefCount().
6070 :
6071 : @return the current reference count for the datasource object itself.
6072 : */
6073 :
6074 5104 : int GDALDataset::GetRefCount() const
6075 : {
6076 5104 : return nRefCount;
6077 : }
6078 :
6079 : /************************************************************************/
6080 : /* GetSummaryRefCount() */
6081 : /************************************************************************/
6082 :
6083 : /**
6084 : \brief Fetch reference count of datasource and all owned layers.
6085 :
6086 : This method is the same as the C function OGR_DS_GetSummaryRefCount().
6087 :
6088 : @deprecated
6089 :
6090 : @return the current summary reference count for the datasource and its layers.
6091 : */
6092 :
6093 0 : int GDALDataset::GetSummaryRefCount() const
6094 :
6095 : {
6096 0 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6097 0 : int nSummaryCount = nRefCount;
6098 0 : GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6099 :
6100 0 : for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6101 0 : nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6102 :
6103 0 : return nSummaryCount;
6104 : }
6105 :
6106 : /************************************************************************/
6107 : /* ICreateLayer() */
6108 : /************************************************************************/
6109 :
6110 : /**
6111 : \brief This method attempts to create a new layer on the dataset with the
6112 : indicated name, coordinate system, geometry type.
6113 :
6114 : This method is reserved to implementation by drivers.
6115 :
6116 : The papszOptions argument can be used to control driver specific creation
6117 : options. These options are normally documented in the format specific
6118 : documentation.
6119 :
6120 : @param pszName the name for the new layer. This should ideally not
6121 : match any existing layer on the datasource.
6122 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
6123 : or NULL if there is no geometry field.
6124 : @param papszOptions a StringList of name=value options. Options are driver
6125 : specific.
6126 :
6127 : @return NULL is returned on failure, or a new OGRLayer handle on success.
6128 :
6129 : */
6130 :
6131 : OGRLayer *
6132 16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6133 : CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6134 : CPL_UNUSED CSLConstList papszOptions)
6135 :
6136 : {
6137 16 : CPLError(CE_Failure, CPLE_NotSupported,
6138 : "CreateLayer() not supported by this dataset.");
6139 :
6140 16 : return nullptr;
6141 : }
6142 :
6143 : /************************************************************************/
6144 : /* CopyLayer() */
6145 : /************************************************************************/
6146 :
6147 : /**
6148 : \brief Duplicate an existing layer.
6149 :
6150 : This method creates a new layer, duplicate the field definitions of the
6151 : source layer and then duplicate each features of the source layer.
6152 : The papszOptions argument
6153 : can be used to control driver specific creation options. These options are
6154 : normally documented in the format specific documentation.
6155 : The source layer may come from another dataset.
6156 :
6157 : This method is the same as the C function GDALDatasetCopyLayer() and the
6158 : deprecated OGR_DS_CopyLayer().
6159 :
6160 : @param poSrcLayer source layer.
6161 : @param pszNewName the name of the layer to create.
6162 : @param papszOptions a StringList of name=value options. Options are driver
6163 : specific. There is a common option to set output layer
6164 : spatial reference: DST_SRSWKT. The option should be in
6165 : WKT format. Starting with GDAL 3.7, the common option
6166 : COPY_MD can be set to NO to prevent the default copying
6167 : of the metadata from the source layer to the target layer.
6168 :
6169 : @return a handle to the layer, or NULL if an error occurs.
6170 : */
6171 :
6172 136 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6173 : char **papszOptions)
6174 :
6175 : {
6176 : /* -------------------------------------------------------------------- */
6177 : /* Create the layer. */
6178 : /* -------------------------------------------------------------------- */
6179 136 : if (!TestCapability(ODsCCreateLayer))
6180 : {
6181 0 : CPLError(CE_Failure, CPLE_NotSupported,
6182 : "This datasource does not support creation of layers.");
6183 0 : return nullptr;
6184 : }
6185 :
6186 136 : const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6187 272 : OGRSpatialReference oDstSpaRef(pszSRSWKT);
6188 136 : oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6189 136 : OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6190 136 : OGRLayer *poDstLayer = nullptr;
6191 :
6192 272 : CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6193 136 : aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6194 136 : aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6195 :
6196 136 : CPLErrorReset();
6197 136 : const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6198 136 : if (nSrcGeomFieldCount == 1)
6199 : {
6200 84 : OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6201 84 : if (pszSRSWKT)
6202 5 : oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6203 84 : poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6204 84 : aosCleanedUpOptions.List());
6205 : }
6206 : else
6207 : {
6208 : poDstLayer =
6209 52 : ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6210 : }
6211 :
6212 136 : if (poDstLayer == nullptr)
6213 0 : return nullptr;
6214 :
6215 136 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6216 : {
6217 135 : char **papszMD = poSrcLayer->GetMetadata();
6218 135 : if (papszMD)
6219 9 : poDstLayer->SetMetadata(papszMD);
6220 : }
6221 :
6222 : /* -------------------------------------------------------------------- */
6223 : /* Add fields. Default to copy all fields, and make sure to */
6224 : /* establish a mapping between indices, rather than names, in */
6225 : /* case the target datasource has altered it (e.g. Shapefile */
6226 : /* limited to 10 char field names). */
6227 : /* -------------------------------------------------------------------- */
6228 136 : const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6229 :
6230 : // Initialize the index-to-index map to -1's.
6231 272 : std::vector<int> anMap(nSrcFieldCount, -1);
6232 :
6233 : // Caution: At the time of writing, the MapInfo driver
6234 : // returns NULL until a field has been added.
6235 136 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6236 136 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6237 293 : for (int iField = 0; iField < nSrcFieldCount; ++iField)
6238 : {
6239 157 : OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6240 314 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6241 :
6242 : // The field may have been already created at layer creation.
6243 157 : int iDstField = -1;
6244 157 : if (poDstFDefn)
6245 157 : iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6246 157 : if (iDstField >= 0)
6247 : {
6248 0 : anMap[iField] = iDstField;
6249 : }
6250 157 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6251 : {
6252 : // Now that we've created a field, GetLayerDefn() won't return NULL.
6253 157 : if (poDstFDefn == nullptr)
6254 0 : poDstFDefn = poDstLayer->GetLayerDefn();
6255 :
6256 : // Sanity check: if it fails, the driver is buggy.
6257 314 : if (poDstFDefn != nullptr &&
6258 157 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6259 : {
6260 0 : CPLError(CE_Warning, CPLE_AppDefined,
6261 : "The output driver has claimed to have added the %s "
6262 : "field, but it did not!",
6263 : oFieldDefn.GetNameRef());
6264 : }
6265 : else
6266 : {
6267 157 : anMap[iField] = nDstFieldCount;
6268 157 : ++nDstFieldCount;
6269 : }
6270 : }
6271 : }
6272 :
6273 : /* -------------------------------------------------------------------- */
6274 136 : std::unique_ptr<OGRCoordinateTransformation> poCT;
6275 136 : const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6276 136 : if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6277 0 : sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6278 : {
6279 0 : poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6280 0 : if (nullptr == poCT)
6281 : {
6282 0 : CPLError(CE_Failure, CPLE_NotSupported,
6283 : "This input/output spatial reference is not supported.");
6284 0 : return nullptr;
6285 : }
6286 : }
6287 : /* -------------------------------------------------------------------- */
6288 : /* Create geometry fields. */
6289 : /* -------------------------------------------------------------------- */
6290 137 : if (nSrcGeomFieldCount > 1 &&
6291 1 : TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6292 : {
6293 :
6294 3 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6295 : {
6296 2 : if (nullptr == pszSRSWKT)
6297 : {
6298 2 : poDstLayer->CreateGeomField(
6299 2 : poSrcDefn->GetGeomFieldDefn(iField));
6300 : }
6301 : else
6302 : {
6303 : OGRGeomFieldDefn *pDstGeomFieldDefn =
6304 0 : poSrcDefn->GetGeomFieldDefn(iField);
6305 0 : pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6306 0 : poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6307 : }
6308 : }
6309 : }
6310 :
6311 : /* -------------------------------------------------------------------- */
6312 : /* Check if the destination layer supports transactions and set a */
6313 : /* default number of features in a single transaction. */
6314 : /* -------------------------------------------------------------------- */
6315 : const int nGroupTransactions =
6316 136 : poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6317 :
6318 : /* -------------------------------------------------------------------- */
6319 : /* Transfer features. */
6320 : /* -------------------------------------------------------------------- */
6321 136 : poSrcLayer->ResetReading();
6322 :
6323 136 : if (nGroupTransactions <= 0)
6324 : {
6325 : while (true)
6326 : {
6327 : auto poFeature =
6328 468 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6329 :
6330 468 : if (poFeature == nullptr)
6331 133 : break;
6332 :
6333 335 : CPLErrorReset();
6334 : auto poDstFeature =
6335 335 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6336 :
6337 335 : if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6338 : OGRERR_NONE)
6339 : {
6340 0 : CPLError(CE_Failure, CPLE_AppDefined,
6341 : "Unable to translate feature " CPL_FRMT_GIB
6342 : " from layer %s.",
6343 0 : poFeature->GetFID(), poSrcDefn->GetName());
6344 0 : return poDstLayer;
6345 : }
6346 :
6347 335 : if (nullptr != poCT)
6348 : {
6349 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6350 : {
6351 0 : OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6352 0 : if (nullptr == pGeom)
6353 0 : continue;
6354 :
6355 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6356 0 : if (eErr == OGRERR_NONE)
6357 0 : continue;
6358 :
6359 0 : CPLError(CE_Failure, CPLE_AppDefined,
6360 : "Unable to transform geometry " CPL_FRMT_GIB
6361 : " from layer %s.",
6362 0 : poFeature->GetFID(), poSrcDefn->GetName());
6363 0 : return poDstLayer;
6364 : }
6365 : }
6366 :
6367 335 : poDstFeature->SetFID(poFeature->GetFID());
6368 :
6369 335 : CPLErrorReset();
6370 335 : if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6371 : {
6372 0 : return poDstLayer;
6373 : }
6374 335 : }
6375 : }
6376 : else
6377 : {
6378 3 : std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6379 : try
6380 : {
6381 3 : apoDstFeatures.resize(nGroupTransactions);
6382 : }
6383 0 : catch (const std::exception &e)
6384 : {
6385 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6386 0 : return poDstLayer;
6387 : }
6388 3 : bool bStopTransfer = false;
6389 6 : while (!bStopTransfer)
6390 : {
6391 : /* --------------------------------------------------------------------
6392 : */
6393 : /* Fill the array with features. */
6394 : /* --------------------------------------------------------------------
6395 : */
6396 : // Number of features in the temporary array.
6397 3 : int nFeatCount = 0; // Used after for.
6398 33 : for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6399 : {
6400 : auto poFeature =
6401 33 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6402 :
6403 33 : if (poFeature == nullptr)
6404 : {
6405 3 : bStopTransfer = true;
6406 3 : break;
6407 : }
6408 :
6409 30 : CPLErrorReset();
6410 30 : apoDstFeatures[nFeatCount] =
6411 60 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6412 :
6413 60 : if (apoDstFeatures[nFeatCount]->SetFrom(
6414 60 : poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6415 : {
6416 0 : CPLError(CE_Failure, CPLE_AppDefined,
6417 : "Unable to translate feature " CPL_FRMT_GIB
6418 : " from layer %s.",
6419 0 : poFeature->GetFID(), poSrcDefn->GetName());
6420 0 : bStopTransfer = true;
6421 0 : poFeature.reset();
6422 0 : break;
6423 : }
6424 :
6425 30 : if (nullptr != poCT)
6426 : {
6427 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6428 : {
6429 : OGRGeometry *pGeom =
6430 0 : apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6431 0 : if (nullptr == pGeom)
6432 0 : continue;
6433 :
6434 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6435 0 : if (eErr == OGRERR_NONE)
6436 0 : continue;
6437 :
6438 0 : CPLError(CE_Failure, CPLE_AppDefined,
6439 : "Unable to transform geometry " CPL_FRMT_GIB
6440 : " from layer %s.",
6441 0 : poFeature->GetFID(), poSrcDefn->GetName());
6442 0 : bStopTransfer = true;
6443 0 : poFeature.reset();
6444 0 : break;
6445 : }
6446 : }
6447 :
6448 30 : if (poFeature)
6449 : {
6450 30 : apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6451 : }
6452 : }
6453 :
6454 3 : CPLErrorReset();
6455 3 : bool bStopTransaction = false;
6456 6 : while (!bStopTransaction)
6457 : {
6458 3 : bStopTransaction = true;
6459 3 : if (poDstLayer->StartTransaction() != OGRERR_NONE)
6460 0 : break;
6461 33 : for (int i = 0; i < nFeatCount; ++i)
6462 : {
6463 30 : if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6464 : OGRERR_NONE)
6465 : {
6466 0 : bStopTransfer = true;
6467 0 : bStopTransaction = false;
6468 0 : break;
6469 : }
6470 30 : apoDstFeatures[i].reset();
6471 : }
6472 3 : if (bStopTransaction)
6473 : {
6474 3 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6475 0 : break;
6476 : }
6477 : else
6478 : {
6479 0 : poDstLayer->RollbackTransaction();
6480 : }
6481 : }
6482 : }
6483 : }
6484 :
6485 136 : return poDstLayer;
6486 : }
6487 :
6488 : /************************************************************************/
6489 : /* DeleteLayer() */
6490 : /************************************************************************/
6491 :
6492 : /**
6493 : \fn GDALDataset::DeleteLayer(int)
6494 : \brief Delete the indicated layer from the datasource.
6495 :
6496 : If this method is supported
6497 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6498 :
6499 : This method is the same as the C function GDALDatasetDeleteLayer() and the
6500 : deprecated OGR_DS_DeleteLayer().
6501 :
6502 : @param iLayer the index of the layer to delete.
6503 :
6504 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6505 : layers is not supported for this datasource.
6506 :
6507 : */
6508 :
6509 389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6510 :
6511 : {
6512 389 : CPLError(CE_Failure, CPLE_NotSupported,
6513 : "DeleteLayer() not supported by this dataset.");
6514 :
6515 389 : return OGRERR_UNSUPPORTED_OPERATION;
6516 : }
6517 :
6518 : /************************************************************************/
6519 : /* GetLayerByName() */
6520 : /************************************************************************/
6521 :
6522 : /**
6523 : \brief Fetch a layer by name.
6524 :
6525 : The returned layer remains owned by the
6526 : GDALDataset and should not be deleted by the application.
6527 :
6528 : This method is the same as the C function GDALDatasetGetLayerByName() and the
6529 : deprecated OGR_DS_GetLayerByName().
6530 :
6531 : @param pszName the layer name of the layer to fetch.
6532 :
6533 : @return the layer, or NULL if Layer is not found or an error occurs.
6534 : */
6535 :
6536 30001 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6537 :
6538 : {
6539 60002 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6540 :
6541 30001 : if (!pszName)
6542 0 : return nullptr;
6543 :
6544 : // First a case sensitive check.
6545 932538 : for (int i = 0; i < GetLayerCount(); ++i)
6546 : {
6547 914349 : OGRLayer *poLayer = GetLayer(i);
6548 :
6549 914349 : if (strcmp(pszName, poLayer->GetName()) == 0)
6550 11812 : return poLayer;
6551 : }
6552 :
6553 : // Then case insensitive.
6554 893794 : for (int i = 0; i < GetLayerCount(); ++i)
6555 : {
6556 875829 : OGRLayer *poLayer = GetLayer(i);
6557 :
6558 875829 : if (EQUAL(pszName, poLayer->GetName()))
6559 224 : return poLayer;
6560 : }
6561 :
6562 17965 : return nullptr;
6563 : }
6564 :
6565 : //! @cond Doxygen_Suppress
6566 : /************************************************************************/
6567 : /* ProcessSQLCreateIndex() */
6568 : /* */
6569 : /* The correct syntax for creating an index in our dialect of */
6570 : /* SQL is: */
6571 : /* */
6572 : /* CREATE INDEX ON <layername> USING <columnname> */
6573 : /************************************************************************/
6574 :
6575 28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6576 :
6577 : {
6578 28 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6579 :
6580 : /* -------------------------------------------------------------------- */
6581 : /* Do some general syntax checking. */
6582 : /* -------------------------------------------------------------------- */
6583 56 : if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6584 84 : !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6585 28 : !EQUAL(papszTokens[4], "USING"))
6586 : {
6587 0 : CSLDestroy(papszTokens);
6588 0 : CPLError(CE_Failure, CPLE_AppDefined,
6589 : "Syntax error in CREATE INDEX command.\n"
6590 : "Was '%s'\n"
6591 : "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6592 : pszSQLCommand);
6593 0 : return OGRERR_FAILURE;
6594 : }
6595 :
6596 : /* -------------------------------------------------------------------- */
6597 : /* Find the named layer. */
6598 : /* -------------------------------------------------------------------- */
6599 28 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6600 28 : if (poLayer == nullptr)
6601 : {
6602 0 : CPLError(CE_Failure, CPLE_AppDefined,
6603 : "CREATE INDEX ON failed, no such layer as `%s'.",
6604 0 : papszTokens[3]);
6605 0 : CSLDestroy(papszTokens);
6606 0 : return OGRERR_FAILURE;
6607 : }
6608 :
6609 : /* -------------------------------------------------------------------- */
6610 : /* Does this layer even support attribute indexes? */
6611 : /* -------------------------------------------------------------------- */
6612 28 : if (poLayer->GetIndex() == nullptr)
6613 : {
6614 0 : CPLError(CE_Failure, CPLE_AppDefined,
6615 : "CREATE INDEX ON not supported by this driver.");
6616 0 : CSLDestroy(papszTokens);
6617 0 : return OGRERR_FAILURE;
6618 : }
6619 :
6620 : /* -------------------------------------------------------------------- */
6621 : /* Find the named field. */
6622 : /* -------------------------------------------------------------------- */
6623 28 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6624 :
6625 28 : CSLDestroy(papszTokens);
6626 :
6627 28 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6628 : {
6629 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6630 : pszSQLCommand);
6631 0 : return OGRERR_FAILURE;
6632 : }
6633 :
6634 : /* -------------------------------------------------------------------- */
6635 : /* Attempt to create the index. */
6636 : /* -------------------------------------------------------------------- */
6637 28 : OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6638 28 : if (eErr == OGRERR_NONE)
6639 : {
6640 28 : eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6641 : }
6642 : else
6643 : {
6644 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
6645 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6646 : }
6647 :
6648 28 : return eErr;
6649 : }
6650 :
6651 : /************************************************************************/
6652 : /* ProcessSQLDropIndex() */
6653 : /* */
6654 : /* The correct syntax for dropping one or more indexes in */
6655 : /* the OGR SQL dialect is: */
6656 : /* */
6657 : /* DROP INDEX ON <layername> [USING <columnname>] */
6658 : /************************************************************************/
6659 :
6660 10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6661 :
6662 : {
6663 10 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6664 :
6665 : /* -------------------------------------------------------------------- */
6666 : /* Do some general syntax checking. */
6667 : /* -------------------------------------------------------------------- */
6668 20 : if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6669 10 : !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6670 30 : !EQUAL(papszTokens[2], "ON") ||
6671 10 : (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6672 : {
6673 0 : CSLDestroy(papszTokens);
6674 0 : CPLError(CE_Failure, CPLE_AppDefined,
6675 : "Syntax error in DROP INDEX command.\n"
6676 : "Was '%s'\n"
6677 : "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6678 : pszSQLCommand);
6679 0 : return OGRERR_FAILURE;
6680 : }
6681 :
6682 : /* -------------------------------------------------------------------- */
6683 : /* Find the named layer. */
6684 : /* -------------------------------------------------------------------- */
6685 10 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6686 10 : if (poLayer == nullptr)
6687 : {
6688 0 : CPLError(CE_Failure, CPLE_AppDefined,
6689 : "DROP INDEX ON failed, no such layer as `%s'.",
6690 0 : papszTokens[3]);
6691 0 : CSLDestroy(papszTokens);
6692 0 : return OGRERR_FAILURE;
6693 : }
6694 :
6695 : /* -------------------------------------------------------------------- */
6696 : /* Does this layer even support attribute indexes? */
6697 : /* -------------------------------------------------------------------- */
6698 10 : if (poLayer->GetIndex() == nullptr)
6699 : {
6700 0 : CPLError(CE_Failure, CPLE_AppDefined,
6701 : "Indexes not supported by this driver.");
6702 0 : CSLDestroy(papszTokens);
6703 0 : return OGRERR_FAILURE;
6704 : }
6705 :
6706 : /* -------------------------------------------------------------------- */
6707 : /* If we were not given a field name, drop all indexes. */
6708 : /* -------------------------------------------------------------------- */
6709 10 : if (CSLCount(papszTokens) == 4)
6710 : {
6711 0 : for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6712 : {
6713 : OGRAttrIndex *poAttrIndex;
6714 :
6715 0 : poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6716 0 : if (poAttrIndex != nullptr)
6717 : {
6718 0 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6719 0 : if (eErr != OGRERR_NONE)
6720 : {
6721 0 : CSLDestroy(papszTokens);
6722 0 : return eErr;
6723 : }
6724 : }
6725 : }
6726 :
6727 0 : CSLDestroy(papszTokens);
6728 0 : return OGRERR_NONE;
6729 : }
6730 :
6731 : /* -------------------------------------------------------------------- */
6732 : /* Find the named field. */
6733 : /* -------------------------------------------------------------------- */
6734 10 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6735 10 : CSLDestroy(papszTokens);
6736 :
6737 10 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6738 : {
6739 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6740 : pszSQLCommand);
6741 0 : return OGRERR_FAILURE;
6742 : }
6743 :
6744 : /* -------------------------------------------------------------------- */
6745 : /* Attempt to drop the index. */
6746 : /* -------------------------------------------------------------------- */
6747 10 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6748 :
6749 10 : return eErr;
6750 : }
6751 :
6752 : /************************************************************************/
6753 : /* ProcessSQLDropTable() */
6754 : /* */
6755 : /* The correct syntax for dropping a table (layer) in the OGR SQL */
6756 : /* dialect is: */
6757 : /* */
6758 : /* DROP TABLE <layername> */
6759 : /************************************************************************/
6760 :
6761 500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6762 :
6763 : {
6764 500 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6765 :
6766 : /* -------------------------------------------------------------------- */
6767 : /* Do some general syntax checking. */
6768 : /* -------------------------------------------------------------------- */
6769 1000 : if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6770 500 : !EQUAL(papszTokens[1], "TABLE"))
6771 : {
6772 0 : CSLDestroy(papszTokens);
6773 0 : CPLError(CE_Failure, CPLE_AppDefined,
6774 : "Syntax error in DROP TABLE command.\n"
6775 : "Was '%s'\n"
6776 : "Should be of form 'DROP TABLE <table>'",
6777 : pszSQLCommand);
6778 0 : return OGRERR_FAILURE;
6779 : }
6780 :
6781 : /* -------------------------------------------------------------------- */
6782 : /* Find the named layer. */
6783 : /* -------------------------------------------------------------------- */
6784 500 : OGRLayer *poLayer = nullptr;
6785 :
6786 500 : int i = 0; // Used after for.
6787 40199 : for (; i < GetLayerCount(); ++i)
6788 : {
6789 40199 : poLayer = GetLayer(i);
6790 :
6791 40199 : if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6792 500 : break;
6793 39699 : poLayer = nullptr;
6794 : }
6795 :
6796 500 : if (poLayer == nullptr)
6797 : {
6798 0 : CPLError(CE_Failure, CPLE_AppDefined,
6799 0 : "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6800 0 : CSLDestroy(papszTokens);
6801 0 : return OGRERR_FAILURE;
6802 : }
6803 :
6804 500 : CSLDestroy(papszTokens);
6805 :
6806 : /* -------------------------------------------------------------------- */
6807 : /* Delete it. */
6808 : /* -------------------------------------------------------------------- */
6809 :
6810 500 : return DeleteLayer(i);
6811 : }
6812 :
6813 : //! @endcond
6814 :
6815 : /************************************************************************/
6816 : /* GDALDatasetParseSQLType() */
6817 : /************************************************************************/
6818 :
6819 : /* All arguments will be altered */
6820 6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6821 : int &nPrecision)
6822 : {
6823 6 : char *pszParenthesis = strchr(pszType, '(');
6824 6 : if (pszParenthesis)
6825 : {
6826 4 : nWidth = atoi(pszParenthesis + 1);
6827 4 : *pszParenthesis = '\0';
6828 4 : char *pszComma = strchr(pszParenthesis + 1, ',');
6829 4 : if (pszComma)
6830 2 : nPrecision = atoi(pszComma + 1);
6831 : }
6832 :
6833 6 : OGRFieldType eType = OFTString;
6834 6 : if (EQUAL(pszType, "INTEGER"))
6835 0 : eType = OFTInteger;
6836 6 : else if (EQUAL(pszType, "INTEGER[]"))
6837 0 : eType = OFTIntegerList;
6838 6 : else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6839 4 : EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6840 4 : EQUAL(pszType, "REAL") /* unofficial alias */)
6841 2 : eType = OFTReal;
6842 4 : else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6843 4 : EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6844 4 : EQUAL(pszType, "REAL[]") /* unofficial alias */)
6845 0 : eType = OFTRealList;
6846 4 : else if (EQUAL(pszType, "CHARACTER") ||
6847 0 : EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6848 0 : EQUAL(pszType, "STRING") /* unofficial alias */ ||
6849 0 : EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6850 4 : eType = OFTString;
6851 0 : else if (EQUAL(pszType, "TEXT[]") ||
6852 0 : EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6853 0 : EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6854 0 : eType = OFTStringList;
6855 0 : else if (EQUAL(pszType, "DATE"))
6856 0 : eType = OFTDate;
6857 0 : else if (EQUAL(pszType, "TIME"))
6858 0 : eType = OFTTime;
6859 0 : else if (EQUAL(pszType, "TIMESTAMP") ||
6860 0 : EQUAL(pszType, "DATETIME") /* unofficial alias */)
6861 0 : eType = OFTDateTime;
6862 : else
6863 0 : CPLError(CE_Warning, CPLE_NotSupported,
6864 : "Unsupported column type '%s'. Defaulting to VARCHAR",
6865 : pszType);
6866 :
6867 6 : return eType;
6868 : }
6869 :
6870 : /************************************************************************/
6871 : /* ProcessSQLAlterTableAddColumn() */
6872 : /* */
6873 : /* The correct syntax for adding a column in the OGR SQL */
6874 : /* dialect is: */
6875 : /* */
6876 : /* ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6877 : /************************************************************************/
6878 :
6879 : //! @cond Doxygen_Suppress
6880 2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6881 :
6882 : {
6883 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6884 :
6885 : /* -------------------------------------------------------------------- */
6886 : /* Do some general syntax checking. */
6887 : /* -------------------------------------------------------------------- */
6888 2 : const char *pszLayerName = nullptr;
6889 2 : const char *pszColumnName = nullptr;
6890 2 : int iTypeIndex = 0;
6891 2 : const int nTokens = CSLCount(papszTokens);
6892 :
6893 2 : if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
6894 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
6895 2 : EQUAL(papszTokens[4], "COLUMN"))
6896 : {
6897 1 : pszLayerName = papszTokens[2];
6898 1 : pszColumnName = papszTokens[5];
6899 1 : iTypeIndex = 6;
6900 : }
6901 1 : else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
6902 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
6903 : {
6904 1 : pszLayerName = papszTokens[2];
6905 1 : pszColumnName = papszTokens[4];
6906 1 : iTypeIndex = 5;
6907 : }
6908 : else
6909 : {
6910 0 : CSLDestroy(papszTokens);
6911 0 : CPLError(CE_Failure, CPLE_AppDefined,
6912 : "Syntax error in ALTER TABLE ADD COLUMN command.\n"
6913 : "Was '%s'\n"
6914 : "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
6915 : "<columnname> <columntype>'",
6916 : pszSQLCommand);
6917 0 : return OGRERR_FAILURE;
6918 : }
6919 :
6920 : /* -------------------------------------------------------------------- */
6921 : /* Merge type components into a single string if there were split */
6922 : /* with spaces */
6923 : /* -------------------------------------------------------------------- */
6924 4 : CPLString osType;
6925 6 : for (int i = iTypeIndex; i < nTokens; ++i)
6926 : {
6927 4 : osType += papszTokens[i];
6928 4 : CPLFree(papszTokens[i]);
6929 : }
6930 2 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
6931 2 : papszTokens[iTypeIndex + 1] = nullptr;
6932 :
6933 : /* -------------------------------------------------------------------- */
6934 : /* Find the named layer. */
6935 : /* -------------------------------------------------------------------- */
6936 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
6937 2 : if (poLayer == nullptr)
6938 : {
6939 0 : CPLError(CE_Failure, CPLE_AppDefined,
6940 : "%s failed, no such layer as `%s'.", pszSQLCommand,
6941 : pszLayerName);
6942 0 : CSLDestroy(papszTokens);
6943 0 : return OGRERR_FAILURE;
6944 : }
6945 :
6946 : /* -------------------------------------------------------------------- */
6947 : /* Add column. */
6948 : /* -------------------------------------------------------------------- */
6949 :
6950 2 : int nWidth = 0;
6951 2 : int nPrecision = 0;
6952 2 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
6953 4 : OGRFieldDefn oFieldDefn(pszColumnName, eType);
6954 2 : oFieldDefn.SetWidth(nWidth);
6955 2 : oFieldDefn.SetPrecision(nPrecision);
6956 :
6957 2 : CSLDestroy(papszTokens);
6958 :
6959 2 : return poLayer->CreateField(&oFieldDefn);
6960 : }
6961 :
6962 : /************************************************************************/
6963 : /* ProcessSQLAlterTableDropColumn() */
6964 : /* */
6965 : /* The correct syntax for dropping a column in the OGR SQL */
6966 : /* dialect is: */
6967 : /* */
6968 : /* ALTER TABLE <layername> DROP [COLUMN] <columnname> */
6969 : /************************************************************************/
6970 :
6971 2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
6972 :
6973 : {
6974 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6975 :
6976 : /* -------------------------------------------------------------------- */
6977 : /* Do some general syntax checking. */
6978 : /* -------------------------------------------------------------------- */
6979 2 : const char *pszLayerName = nullptr;
6980 2 : const char *pszColumnName = nullptr;
6981 3 : if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
6982 4 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
6983 1 : EQUAL(papszTokens[4], "COLUMN"))
6984 : {
6985 1 : pszLayerName = papszTokens[2];
6986 1 : pszColumnName = papszTokens[5];
6987 : }
6988 2 : else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
6989 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
6990 : {
6991 1 : pszLayerName = papszTokens[2];
6992 1 : pszColumnName = papszTokens[4];
6993 : }
6994 : else
6995 : {
6996 0 : CSLDestroy(papszTokens);
6997 0 : CPLError(CE_Failure, CPLE_AppDefined,
6998 : "Syntax error in ALTER TABLE DROP COLUMN command.\n"
6999 : "Was '%s'\n"
7000 : "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7001 : "<columnname>'",
7002 : pszSQLCommand);
7003 0 : return OGRERR_FAILURE;
7004 : }
7005 :
7006 : /* -------------------------------------------------------------------- */
7007 : /* Find the named layer. */
7008 : /* -------------------------------------------------------------------- */
7009 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7010 2 : if (poLayer == nullptr)
7011 : {
7012 0 : CPLError(CE_Failure, CPLE_AppDefined,
7013 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7014 : pszLayerName);
7015 0 : CSLDestroy(papszTokens);
7016 0 : return OGRERR_FAILURE;
7017 : }
7018 :
7019 : /* -------------------------------------------------------------------- */
7020 : /* Find the field. */
7021 : /* -------------------------------------------------------------------- */
7022 :
7023 2 : int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7024 2 : if (nFieldIndex < 0)
7025 : {
7026 0 : CPLError(CE_Failure, CPLE_AppDefined,
7027 : "%s failed, no such field as `%s'.", pszSQLCommand,
7028 : pszColumnName);
7029 0 : CSLDestroy(papszTokens);
7030 0 : return OGRERR_FAILURE;
7031 : }
7032 :
7033 : /* -------------------------------------------------------------------- */
7034 : /* Remove it. */
7035 : /* -------------------------------------------------------------------- */
7036 :
7037 2 : CSLDestroy(papszTokens);
7038 :
7039 2 : return poLayer->DeleteField(nFieldIndex);
7040 : }
7041 :
7042 : /************************************************************************/
7043 : /* ProcessSQLAlterTableRenameColumn() */
7044 : /* */
7045 : /* The correct syntax for renaming a column in the OGR SQL */
7046 : /* dialect is: */
7047 : /* */
7048 : /* ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7049 : /************************************************************************/
7050 :
7051 2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7052 :
7053 : {
7054 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7055 :
7056 : /* -------------------------------------------------------------------- */
7057 : /* Do some general syntax checking. */
7058 : /* -------------------------------------------------------------------- */
7059 2 : const char *pszLayerName = nullptr;
7060 2 : const char *pszOldColName = nullptr;
7061 2 : const char *pszNewColName = nullptr;
7062 3 : if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7063 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7064 3 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7065 : {
7066 1 : pszLayerName = papszTokens[2];
7067 1 : pszOldColName = papszTokens[5];
7068 1 : pszNewColName = papszTokens[7];
7069 : }
7070 2 : else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7071 1 : EQUAL(papszTokens[1], "TABLE") &&
7072 2 : EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7073 : {
7074 1 : pszLayerName = papszTokens[2];
7075 1 : pszOldColName = papszTokens[4];
7076 1 : pszNewColName = papszTokens[6];
7077 : }
7078 : else
7079 : {
7080 0 : CSLDestroy(papszTokens);
7081 0 : CPLError(CE_Failure, CPLE_AppDefined,
7082 : "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7083 : "Was '%s'\n"
7084 : "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7085 : "<columnname> TO <newname>'",
7086 : pszSQLCommand);
7087 0 : return OGRERR_FAILURE;
7088 : }
7089 :
7090 : /* -------------------------------------------------------------------- */
7091 : /* Find the named layer. */
7092 : /* -------------------------------------------------------------------- */
7093 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7094 2 : if (poLayer == nullptr)
7095 : {
7096 0 : CPLError(CE_Failure, CPLE_AppDefined,
7097 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7098 : pszLayerName);
7099 0 : CSLDestroy(papszTokens);
7100 0 : return OGRERR_FAILURE;
7101 : }
7102 :
7103 : /* -------------------------------------------------------------------- */
7104 : /* Find the field. */
7105 : /* -------------------------------------------------------------------- */
7106 :
7107 : const int nFieldIndex =
7108 2 : poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7109 2 : if (nFieldIndex < 0)
7110 : {
7111 0 : CPLError(CE_Failure, CPLE_AppDefined,
7112 : "%s failed, no such field as `%s'.", pszSQLCommand,
7113 : pszOldColName);
7114 0 : CSLDestroy(papszTokens);
7115 0 : return OGRERR_FAILURE;
7116 : }
7117 :
7118 : /* -------------------------------------------------------------------- */
7119 : /* Rename column. */
7120 : /* -------------------------------------------------------------------- */
7121 : OGRFieldDefn *poOldFieldDefn =
7122 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7123 4 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7124 2 : oNewFieldDefn.SetName(pszNewColName);
7125 :
7126 2 : CSLDestroy(papszTokens);
7127 :
7128 2 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7129 2 : ALTER_NAME_FLAG);
7130 : }
7131 :
7132 : /************************************************************************/
7133 : /* ProcessSQLAlterTableAlterColumn() */
7134 : /* */
7135 : /* The correct syntax for altering the type of a column in the */
7136 : /* OGR SQL dialect is: */
7137 : /* */
7138 : /* ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7139 : /************************************************************************/
7140 :
7141 4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7142 :
7143 : {
7144 4 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7145 :
7146 : /* -------------------------------------------------------------------- */
7147 : /* Do some general syntax checking. */
7148 : /* -------------------------------------------------------------------- */
7149 4 : const char *pszLayerName = nullptr;
7150 4 : const char *pszColumnName = nullptr;
7151 4 : int iTypeIndex = 0;
7152 4 : const int nTokens = CSLCount(papszTokens);
7153 :
7154 4 : if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7155 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7156 2 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7157 : {
7158 2 : pszLayerName = papszTokens[2];
7159 2 : pszColumnName = papszTokens[5];
7160 2 : iTypeIndex = 7;
7161 : }
7162 2 : else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7163 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7164 2 : EQUAL(papszTokens[5], "TYPE"))
7165 : {
7166 2 : pszLayerName = papszTokens[2];
7167 2 : pszColumnName = papszTokens[4];
7168 2 : iTypeIndex = 6;
7169 : }
7170 : else
7171 : {
7172 0 : CSLDestroy(papszTokens);
7173 0 : CPLError(CE_Failure, CPLE_AppDefined,
7174 : "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7175 : "Was '%s'\n"
7176 : "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7177 : "<columnname> TYPE <columntype>'",
7178 : pszSQLCommand);
7179 0 : return OGRERR_FAILURE;
7180 : }
7181 :
7182 : /* -------------------------------------------------------------------- */
7183 : /* Merge type components into a single string if there were split */
7184 : /* with spaces */
7185 : /* -------------------------------------------------------------------- */
7186 8 : CPLString osType;
7187 8 : for (int i = iTypeIndex; i < nTokens; ++i)
7188 : {
7189 4 : osType += papszTokens[i];
7190 4 : CPLFree(papszTokens[i]);
7191 : }
7192 4 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7193 4 : papszTokens[iTypeIndex + 1] = nullptr;
7194 :
7195 : /* -------------------------------------------------------------------- */
7196 : /* Find the named layer. */
7197 : /* -------------------------------------------------------------------- */
7198 4 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7199 4 : if (poLayer == nullptr)
7200 : {
7201 0 : CPLError(CE_Failure, CPLE_AppDefined,
7202 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7203 : pszLayerName);
7204 0 : CSLDestroy(papszTokens);
7205 0 : return OGRERR_FAILURE;
7206 : }
7207 :
7208 : /* -------------------------------------------------------------------- */
7209 : /* Find the field. */
7210 : /* -------------------------------------------------------------------- */
7211 :
7212 : const int nFieldIndex =
7213 4 : poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7214 4 : if (nFieldIndex < 0)
7215 : {
7216 0 : CPLError(CE_Failure, CPLE_AppDefined,
7217 : "%s failed, no such field as `%s'.", pszSQLCommand,
7218 : pszColumnName);
7219 0 : CSLDestroy(papszTokens);
7220 0 : return OGRERR_FAILURE;
7221 : }
7222 :
7223 : /* -------------------------------------------------------------------- */
7224 : /* Alter column. */
7225 : /* -------------------------------------------------------------------- */
7226 :
7227 : OGRFieldDefn *poOldFieldDefn =
7228 4 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7229 8 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7230 :
7231 4 : int nWidth = 0;
7232 4 : int nPrecision = 0;
7233 4 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7234 4 : oNewFieldDefn.SetType(eType);
7235 4 : oNewFieldDefn.SetWidth(nWidth);
7236 4 : oNewFieldDefn.SetPrecision(nPrecision);
7237 :
7238 4 : int l_nFlags = 0;
7239 4 : if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7240 2 : l_nFlags |= ALTER_TYPE_FLAG;
7241 4 : if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7242 0 : poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7243 4 : l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7244 :
7245 4 : CSLDestroy(papszTokens);
7246 :
7247 4 : if (l_nFlags == 0)
7248 0 : return OGRERR_NONE;
7249 :
7250 4 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7251 : }
7252 :
7253 : //! @endcond
7254 :
7255 : /************************************************************************/
7256 : /* ExecuteSQL() */
7257 : /************************************************************************/
7258 :
7259 : /**
7260 : \brief Execute an SQL statement against the data store.
7261 :
7262 : The result of an SQL query is either NULL for statements that are in error,
7263 : or that have no results set, or an OGRLayer pointer representing a results
7264 : set from the query. Note that this OGRLayer is in addition to the layers
7265 : in the data store and must be destroyed with
7266 : ReleaseResultSet() before the dataset is closed
7267 : (destroyed).
7268 :
7269 : This method is the same as the C function GDALDatasetExecuteSQL() and the
7270 : deprecated OGR_DS_ExecuteSQL().
7271 :
7272 : For more information on the SQL dialect supported internally by OGR
7273 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7274 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7275 : to the underlying RDBMS.
7276 :
7277 : Starting with OGR 1.10, the <a
7278 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7279 : also be used.
7280 :
7281 : @param pszStatement the SQL statement to execute.
7282 : @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7283 : @param pszDialect allows control of the statement dialect. If set to NULL, the
7284 : OGR SQL engine will be used, except for RDBMS drivers that will use their
7285 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
7286 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7287 :
7288 : @return an OGRLayer containing the results of the query. Deallocate with
7289 : ReleaseResultSet().
7290 :
7291 : */
7292 :
7293 3575 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7294 : OGRGeometry *poSpatialFilter,
7295 : const char *pszDialect)
7296 :
7297 : {
7298 3575 : return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7299 : }
7300 :
7301 : //! @cond Doxygen_Suppress
7302 : OGRLayer *
7303 3583 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7304 : const char *pszDialect,
7305 : swq_select_parse_options *poSelectParseOptions)
7306 :
7307 : {
7308 3583 : if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7309 : {
7310 : #ifdef SQLITE_ENABLED
7311 650 : return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7312 650 : pszDialect);
7313 : #else
7314 : CPLError(CE_Failure, CPLE_NotSupported,
7315 : "The SQLite driver needs to be compiled to support the "
7316 : "SQLite SQL dialect");
7317 : return nullptr;
7318 : #endif
7319 : }
7320 :
7321 2933 : if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7322 14 : !EQUAL(pszDialect, "OGRSQL"))
7323 : {
7324 6 : std::string osDialectList = "'OGRSQL'";
7325 : #ifdef SQLITE_ENABLED
7326 3 : osDialectList += ", 'SQLITE'";
7327 : #endif
7328 : const char *pszDialects =
7329 3 : GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7330 3 : if (pszDialects)
7331 : {
7332 : const CPLStringList aosTokens(
7333 0 : CSLTokenizeString2(pszDialects, " ", 0));
7334 0 : for (int i = 0; i < aosTokens.size(); ++i)
7335 : {
7336 0 : if (!EQUAL(aosTokens[i], "OGRSQL") &&
7337 0 : !EQUAL(aosTokens[i], "SQLITE"))
7338 : {
7339 0 : osDialectList += ", '";
7340 0 : osDialectList += aosTokens[i];
7341 0 : osDialectList += "'";
7342 : }
7343 : }
7344 : }
7345 3 : CPLError(CE_Warning, CPLE_NotSupported,
7346 : "Dialect '%s' is unsupported. Only supported dialects are %s. "
7347 : "Defaulting to OGRSQL",
7348 : pszDialect, osDialectList.c_str());
7349 : }
7350 :
7351 : /* -------------------------------------------------------------------- */
7352 : /* Handle CREATE INDEX statements specially. */
7353 : /* -------------------------------------------------------------------- */
7354 2933 : if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7355 : {
7356 28 : ProcessSQLCreateIndex(pszStatement);
7357 28 : return nullptr;
7358 : }
7359 :
7360 : /* -------------------------------------------------------------------- */
7361 : /* Handle DROP INDEX statements specially. */
7362 : /* -------------------------------------------------------------------- */
7363 2905 : if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7364 : {
7365 10 : ProcessSQLDropIndex(pszStatement);
7366 10 : return nullptr;
7367 : }
7368 :
7369 : /* -------------------------------------------------------------------- */
7370 : /* Handle DROP TABLE statements specially. */
7371 : /* -------------------------------------------------------------------- */
7372 2895 : if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7373 : {
7374 500 : ProcessSQLDropTable(pszStatement);
7375 500 : return nullptr;
7376 : }
7377 :
7378 : /* -------------------------------------------------------------------- */
7379 : /* Handle ALTER TABLE statements specially. */
7380 : /* -------------------------------------------------------------------- */
7381 2395 : if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7382 : {
7383 11 : char **papszTokens = CSLTokenizeString(pszStatement);
7384 11 : const int nTokens = CSLCount(papszTokens);
7385 11 : if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7386 : {
7387 2 : ProcessSQLAlterTableAddColumn(pszStatement);
7388 2 : CSLDestroy(papszTokens);
7389 2 : return nullptr;
7390 : }
7391 9 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7392 : {
7393 2 : ProcessSQLAlterTableDropColumn(pszStatement);
7394 2 : CSLDestroy(papszTokens);
7395 2 : return nullptr;
7396 : }
7397 7 : else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7398 1 : EQUAL(papszTokens[4], "TO"))
7399 : {
7400 1 : const char *pszSrcTableName = papszTokens[2];
7401 1 : const char *pszDstTableName = papszTokens[5];
7402 1 : auto poSrcLayer = GetLayerByName(pszSrcTableName);
7403 1 : if (poSrcLayer)
7404 : {
7405 1 : CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7406 : }
7407 : else
7408 : {
7409 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7410 : }
7411 1 : CSLDestroy(papszTokens);
7412 1 : return nullptr;
7413 : }
7414 6 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7415 : {
7416 2 : ProcessSQLAlterTableRenameColumn(pszStatement);
7417 2 : CSLDestroy(papszTokens);
7418 2 : return nullptr;
7419 : }
7420 4 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7421 : {
7422 4 : ProcessSQLAlterTableAlterColumn(pszStatement);
7423 4 : CSLDestroy(papszTokens);
7424 4 : return nullptr;
7425 : }
7426 : else
7427 : {
7428 0 : CPLError(CE_Failure, CPLE_AppDefined,
7429 : "Unsupported ALTER TABLE command : %s", pszStatement);
7430 0 : CSLDestroy(papszTokens);
7431 0 : return nullptr;
7432 : }
7433 : }
7434 :
7435 : /* -------------------------------------------------------------------- */
7436 : /* Preparse the SQL statement. */
7437 : /* -------------------------------------------------------------------- */
7438 2384 : swq_select *psSelectInfo = new swq_select();
7439 2384 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7440 2384 : if (poSelectParseOptions != nullptr)
7441 8 : poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7442 2384 : if (psSelectInfo->preparse(pszStatement,
7443 2384 : poCustomFuncRegistrar != nullptr) != CE_None)
7444 : {
7445 143 : delete psSelectInfo;
7446 143 : return nullptr;
7447 : }
7448 :
7449 : /* -------------------------------------------------------------------- */
7450 : /* If there is no UNION ALL, build result layer. */
7451 : /* -------------------------------------------------------------------- */
7452 2241 : if (psSelectInfo->poOtherSelect == nullptr)
7453 : {
7454 2235 : return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7455 2235 : pszDialect, poSelectParseOptions);
7456 : }
7457 :
7458 : /* -------------------------------------------------------------------- */
7459 : /* Build result union layer. */
7460 : /* -------------------------------------------------------------------- */
7461 6 : int nSrcLayers = 0;
7462 6 : OGRLayer **papoSrcLayers = nullptr;
7463 :
7464 6 : do
7465 : {
7466 12 : swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7467 12 : psSelectInfo->poOtherSelect = nullptr;
7468 :
7469 12 : OGRLayer *poLayer = BuildLayerFromSelectInfo(
7470 : psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7471 12 : if (poLayer == nullptr)
7472 : {
7473 : // Each source layer owns an independent select info.
7474 0 : for (int i = 0; i < nSrcLayers; ++i)
7475 0 : delete papoSrcLayers[i];
7476 0 : CPLFree(papoSrcLayers);
7477 :
7478 : // So we just have to destroy the remaining select info.
7479 0 : delete psNextSelectInfo;
7480 :
7481 0 : return nullptr;
7482 : }
7483 : else
7484 : {
7485 24 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7486 12 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7487 12 : papoSrcLayers[nSrcLayers] = poLayer;
7488 12 : ++nSrcLayers;
7489 :
7490 12 : psSelectInfo = psNextSelectInfo;
7491 : }
7492 12 : } while (psSelectInfo != nullptr);
7493 :
7494 6 : return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7495 : }
7496 :
7497 : //! @endcond
7498 :
7499 : /************************************************************************/
7500 : /* AbortSQL() */
7501 : /************************************************************************/
7502 :
7503 : /**
7504 : \brief Abort any SQL statement running in the data store.
7505 :
7506 : This function can be safely called from any thread (pending that the dataset
7507 : object is still alive). Driver implementations will make sure that it can be
7508 : called in a thread-safe way.
7509 :
7510 : This might not be implemented by all drivers. At time of writing, only SQLite,
7511 : GPKG and PG drivers implement it
7512 :
7513 : This method is the same as the C method GDALDatasetAbortSQL()
7514 :
7515 : @since GDAL 3.2.0
7516 :
7517 :
7518 : */
7519 :
7520 0 : OGRErr GDALDataset::AbortSQL()
7521 : {
7522 0 : CPLError(CE_Failure, CPLE_NotSupported,
7523 : "AbortSQL is not supported for this driver.");
7524 0 : return OGRERR_UNSUPPORTED_OPERATION;
7525 : }
7526 :
7527 : /************************************************************************/
7528 : /* BuildLayerFromSelectInfo() */
7529 : /************************************************************************/
7530 :
7531 : struct GDALSQLParseInfo
7532 : {
7533 : swq_field_list sFieldList;
7534 : int nExtraDSCount;
7535 : GDALDataset **papoExtraDS;
7536 : char *pszWHERE;
7537 : };
7538 :
7539 2247 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7540 : swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7541 : const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7542 : {
7543 4494 : std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7544 :
7545 2247 : std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7546 : GDALSQLParseInfo *psParseInfo =
7547 2247 : BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7548 :
7549 2247 : if (psParseInfo)
7550 : {
7551 2212 : const auto nErrorCounter = CPLGetErrorCounter();
7552 4424 : poResults = std::make_unique<OGRGenSQLResultsLayer>(
7553 2212 : this, std::move(psSelectInfoUnique), poSpatialFilter,
7554 4424 : psParseInfo->pszWHERE, pszDialect);
7555 2289 : if (CPLGetErrorCounter() > nErrorCounter &&
7556 77 : CPLGetLastErrorType() != CE_None)
7557 77 : poResults.reset();
7558 : }
7559 :
7560 2247 : DestroyParseInfo(psParseInfo);
7561 :
7562 4494 : return poResults.release();
7563 : }
7564 :
7565 : /************************************************************************/
7566 : /* DestroyParseInfo() */
7567 : /************************************************************************/
7568 :
7569 : //! @cond Doxygen_Suppress
7570 2316 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7571 : {
7572 2316 : if (psParseInfo == nullptr)
7573 35 : return;
7574 :
7575 2281 : CPLFree(psParseInfo->sFieldList.names);
7576 2281 : CPLFree(psParseInfo->sFieldList.types);
7577 2281 : CPLFree(psParseInfo->sFieldList.table_ids);
7578 2281 : CPLFree(psParseInfo->sFieldList.ids);
7579 :
7580 : // Release the datasets we have opened with OGROpenShared()
7581 : // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7582 : // has taken a reference on them, which it will release in its
7583 : // destructor.
7584 2288 : for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7585 7 : GDALClose(psParseInfo->papoExtraDS[iEDS]);
7586 :
7587 2281 : CPLFree(psParseInfo->papoExtraDS);
7588 2281 : CPLFree(psParseInfo->pszWHERE);
7589 2281 : CPLFree(psParseInfo);
7590 : }
7591 :
7592 : /************************************************************************/
7593 : /* BuildParseInfo() */
7594 : /************************************************************************/
7595 :
7596 : GDALSQLParseInfo *
7597 2281 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7598 : swq_select_parse_options *poSelectParseOptions)
7599 : {
7600 2281 : int nFirstLayerFirstSpecialFieldIndex = 0;
7601 :
7602 : GDALSQLParseInfo *psParseInfo =
7603 2281 : static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7604 :
7605 : /* -------------------------------------------------------------------- */
7606 : /* Validate that all the source tables are recognized, count */
7607 : /* fields. */
7608 : /* -------------------------------------------------------------------- */
7609 2281 : int nFieldCount = 0;
7610 :
7611 4630 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7612 : {
7613 2352 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7614 2352 : GDALDataset *poTableDS = this;
7615 :
7616 2352 : if (psTableDef->data_source != nullptr)
7617 : {
7618 7 : poTableDS = GDALDataset::FromHandle(
7619 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7620 7 : if (poTableDS == nullptr)
7621 : {
7622 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
7623 0 : CPLError(CE_Failure, CPLE_AppDefined,
7624 : "Unable to open secondary datasource "
7625 : "`%s' required by JOIN.",
7626 : psTableDef->data_source);
7627 :
7628 0 : DestroyParseInfo(psParseInfo);
7629 0 : return nullptr;
7630 : }
7631 :
7632 : // Keep in an array to release at the end of this function.
7633 14 : psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7634 7 : psParseInfo->papoExtraDS,
7635 7 : sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7636 7 : psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7637 : }
7638 :
7639 : OGRLayer *poSrcLayer =
7640 2352 : poTableDS->GetLayerByName(psTableDef->table_name);
7641 :
7642 2352 : if (poSrcLayer == nullptr)
7643 : {
7644 3 : CPLError(CE_Failure, CPLE_AppDefined,
7645 : "SELECT from table %s failed, no such table/featureclass.",
7646 : psTableDef->table_name);
7647 :
7648 3 : DestroyParseInfo(psParseInfo);
7649 3 : return nullptr;
7650 : }
7651 :
7652 2349 : nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7653 2349 : if (iTable == 0 ||
7654 34 : (poSelectParseOptions &&
7655 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7656 2312 : nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7657 :
7658 2349 : const char *pszFID = poSrcLayer->GetFIDColumn();
7659 2960 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7660 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7661 561 : nFieldCount++;
7662 : }
7663 :
7664 : /* -------------------------------------------------------------------- */
7665 : /* Build the field list for all indicated tables. */
7666 : /* -------------------------------------------------------------------- */
7667 :
7668 2278 : psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7669 2278 : psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7670 :
7671 2278 : psParseInfo->sFieldList.count = 0;
7672 2278 : psParseInfo->sFieldList.names = static_cast<char **>(
7673 2278 : CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7674 4556 : psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7675 2278 : sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7676 2278 : psParseInfo->sFieldList.table_ids = static_cast<int *>(
7677 2278 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7678 2278 : psParseInfo->sFieldList.ids = static_cast<int *>(
7679 2278 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7680 :
7681 2278 : bool bIsFID64 = false;
7682 4627 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7683 : {
7684 2349 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7685 2349 : GDALDataset *poTableDS = this;
7686 :
7687 2349 : if (psTableDef->data_source != nullptr)
7688 : {
7689 7 : poTableDS = GDALDataset::FromHandle(
7690 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7691 7 : CPLAssert(poTableDS != nullptr);
7692 7 : poTableDS->Dereference();
7693 : }
7694 :
7695 : OGRLayer *poSrcLayer =
7696 2349 : poTableDS->GetLayerByName(psTableDef->table_name);
7697 :
7698 2349 : for (int iField = 0;
7699 18567 : iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7700 : {
7701 : OGRFieldDefn *poFDefn =
7702 16218 : poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7703 16218 : const int iOutField = psParseInfo->sFieldList.count++;
7704 32436 : psParseInfo->sFieldList.names[iOutField] =
7705 16218 : const_cast<char *>(poFDefn->GetNameRef());
7706 16218 : if (poFDefn->GetType() == OFTInteger)
7707 : {
7708 4089 : if (poFDefn->GetSubType() == OFSTBoolean)
7709 160 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7710 : else
7711 3929 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7712 : }
7713 12129 : else if (poFDefn->GetType() == OFTInteger64)
7714 : {
7715 759 : if (poFDefn->GetSubType() == OFSTBoolean)
7716 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7717 : else
7718 759 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7719 : }
7720 11370 : else if (poFDefn->GetType() == OFTReal)
7721 2721 : psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7722 8649 : else if (poFDefn->GetType() == OFTString)
7723 5595 : psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7724 3054 : else if (poFDefn->GetType() == OFTTime)
7725 83 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7726 2971 : else if (poFDefn->GetType() == OFTDate)
7727 143 : psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7728 2828 : else if (poFDefn->GetType() == OFTDateTime)
7729 939 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7730 : else
7731 1889 : psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7732 :
7733 16218 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7734 16218 : psParseInfo->sFieldList.ids[iOutField] = iField;
7735 : }
7736 :
7737 2349 : if (iTable == 0)
7738 : {
7739 2278 : nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7740 : }
7741 :
7742 2349 : if (iTable == 0 ||
7743 34 : (poSelectParseOptions &&
7744 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7745 : {
7746 :
7747 2312 : for (int iField = 0;
7748 4273 : iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7749 : iField++)
7750 : {
7751 : OGRGeomFieldDefn *poFDefn =
7752 1961 : poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7753 1961 : const int iOutField = psParseInfo->sFieldList.count++;
7754 3922 : psParseInfo->sFieldList.names[iOutField] =
7755 1961 : const_cast<char *>(poFDefn->GetNameRef());
7756 1961 : if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7757 1141 : psParseInfo->sFieldList.names[iOutField] =
7758 : const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7759 1961 : psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7760 :
7761 1961 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7762 1961 : psParseInfo->sFieldList.ids[iOutField] =
7763 1961 : GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7764 : poSrcLayer->GetLayerDefn(), iField);
7765 : }
7766 : }
7767 :
7768 2350 : if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7769 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7770 : {
7771 1 : bIsFID64 = true;
7772 : }
7773 : }
7774 :
7775 : /* -------------------------------------------------------------------- */
7776 : /* Expand '*' in 'SELECT *' now before we add the pseudo fields */
7777 : /* -------------------------------------------------------------------- */
7778 2278 : const bool bAlwaysPrefixWithTableName =
7779 2320 : poSelectParseOptions &&
7780 42 : poSelectParseOptions->bAlwaysPrefixWithTableName;
7781 2278 : if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7782 2278 : bAlwaysPrefixWithTableName) != CE_None)
7783 : {
7784 2 : DestroyParseInfo(psParseInfo);
7785 2 : return nullptr;
7786 : }
7787 :
7788 13656 : for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7789 : {
7790 11380 : psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7791 11380 : const_cast<char *>(SpecialFieldNames[iField]);
7792 11380 : psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7793 11380 : (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7794 : : SpecialFieldTypes[iField];
7795 11380 : psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7796 11380 : psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7797 11380 : nFirstLayerFirstSpecialFieldIndex + iField;
7798 11380 : psParseInfo->sFieldList.count++;
7799 : }
7800 :
7801 : /* In the case a layer has an explicit FID column name, then add it */
7802 : /* so it can be selected */
7803 4623 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7804 : {
7805 2347 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7806 2347 : GDALDataset *poTableDS = this;
7807 :
7808 2347 : if (psTableDef->data_source != nullptr)
7809 : {
7810 7 : poTableDS = GDALDataset::FromHandle(
7811 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7812 7 : CPLAssert(poTableDS != nullptr);
7813 7 : poTableDS->Dereference();
7814 : }
7815 :
7816 : OGRLayer *poSrcLayer =
7817 2347 : poTableDS->GetLayerByName(psTableDef->table_name);
7818 :
7819 2347 : const char *pszFID = poSrcLayer->GetFIDColumn();
7820 2958 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7821 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7822 : {
7823 561 : const int iOutField = psParseInfo->sFieldList.count++;
7824 561 : psParseInfo->sFieldList.names[iOutField] =
7825 : const_cast<char *>(pszFID);
7826 561 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7827 0 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7828 : {
7829 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7830 : }
7831 : else
7832 : {
7833 561 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7834 : }
7835 561 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7836 1122 : psParseInfo->sFieldList.ids[iOutField] =
7837 561 : poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7838 : }
7839 : }
7840 :
7841 : /* -------------------------------------------------------------------- */
7842 : /* Finish the parse operation. */
7843 : /* -------------------------------------------------------------------- */
7844 2276 : if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7845 : CE_None)
7846 : {
7847 30 : DestroyParseInfo(psParseInfo);
7848 30 : return nullptr;
7849 : }
7850 :
7851 : /* -------------------------------------------------------------------- */
7852 : /* Extract the WHERE expression to use separately. */
7853 : /* -------------------------------------------------------------------- */
7854 2246 : if (psSelectInfo->where_expr != nullptr)
7855 : {
7856 963 : psParseInfo->pszWHERE =
7857 963 : psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7858 : // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7859 : }
7860 :
7861 2246 : return psParseInfo;
7862 : }
7863 :
7864 : //! @endcond
7865 :
7866 : /************************************************************************/
7867 : /* ReleaseResultSet() */
7868 : /************************************************************************/
7869 :
7870 : /**
7871 : \brief Release results of ExecuteSQL().
7872 :
7873 : This method should only be used to deallocate OGRLayers resulting from
7874 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
7875 : results set before destroying the GDALDataset may cause errors.
7876 :
7877 : This method is the same as the C function GDALDatasetReleaseResultSet() and the
7878 : deprecated OGR_DS_ReleaseResultSet().
7879 :
7880 : @param poResultsSet the result of a previous ExecuteSQL() call.
7881 : */
7882 :
7883 2162 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7884 :
7885 : {
7886 2162 : delete poResultsSet;
7887 2162 : }
7888 :
7889 : /************************************************************************/
7890 : /* GetStyleTable() */
7891 : /************************************************************************/
7892 :
7893 : /**
7894 : \brief Returns dataset style table.
7895 :
7896 : This method is the same as the C function GDALDatasetGetStyleTable() and the
7897 : deprecated OGR_DS_GetStyleTable().
7898 :
7899 : @return pointer to a style table which should not be modified or freed by the
7900 : caller.
7901 : */
7902 :
7903 933 : OGRStyleTable *GDALDataset::GetStyleTable()
7904 : {
7905 933 : return m_poStyleTable;
7906 : }
7907 :
7908 : /************************************************************************/
7909 : /* SetStyleTableDirectly() */
7910 : /************************************************************************/
7911 :
7912 : /**
7913 : \brief Set dataset style table.
7914 :
7915 : This method operate exactly as SetStyleTable() except that it
7916 : assumes ownership of the passed table.
7917 :
7918 : This method is the same as the C function GDALDatasetSetStyleTableDirectly()
7919 : and the deprecated OGR_DS_SetStyleTableDirectly().
7920 :
7921 : @param poStyleTable pointer to style table to set
7922 :
7923 : */
7924 0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
7925 : {
7926 0 : if (m_poStyleTable)
7927 0 : delete m_poStyleTable;
7928 0 : m_poStyleTable = poStyleTable;
7929 0 : }
7930 :
7931 : /************************************************************************/
7932 : /* SetStyleTable() */
7933 : /************************************************************************/
7934 :
7935 : /**
7936 : \brief Set dataset style table.
7937 :
7938 : This method operate exactly as SetStyleTableDirectly() except
7939 : that it does not assume ownership of the passed table.
7940 :
7941 : This method is the same as the C function GDALDatasetSetStyleTable() and the
7942 : deprecated OGR_DS_SetStyleTable().
7943 :
7944 : @param poStyleTable pointer to style table to set
7945 :
7946 : */
7947 :
7948 929 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
7949 : {
7950 929 : if (m_poStyleTable)
7951 0 : delete m_poStyleTable;
7952 929 : if (poStyleTable)
7953 1 : m_poStyleTable = poStyleTable->Clone();
7954 929 : }
7955 :
7956 : /************************************************************************/
7957 : /* IsGenericSQLDialect() */
7958 : /************************************************************************/
7959 :
7960 : //! @cond Doxygen_Suppress
7961 1748 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
7962 : {
7963 3188 : return pszDialect != nullptr &&
7964 3188 : (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
7965 : }
7966 :
7967 : //! @endcond
7968 :
7969 : /************************************************************************/
7970 : /* GetLayerCount() */
7971 : /************************************************************************/
7972 :
7973 : /**
7974 : \brief Get the number of layers in this dataset.
7975 :
7976 : This method is the same as the C function GDALDatasetGetLayerCount(),
7977 : and the deprecated OGR_DS_GetLayerCount().
7978 :
7979 : Note that even if this method is const, there is no guarantee it can be
7980 : safely called by concurrent threads on the same GDALDataset object.
7981 :
7982 : @return layer count.
7983 : */
7984 :
7985 117238 : int GDALDataset::GetLayerCount() const
7986 : {
7987 117238 : return 0;
7988 : }
7989 :
7990 : /************************************************************************/
7991 : /* GetLayer() */
7992 : /************************************************************************/
7993 :
7994 : /**
7995 : \fn const GDALDataset::GetLayer(int) const
7996 : \brief Fetch a layer by index.
7997 :
7998 : The returned layer remains owned by the
7999 : GDALDataset and should not be deleted by the application.
8000 :
8001 : Note that even if this method is const, there is no guarantee it can be
8002 : safely called by concurrent threads on the same GDALDataset object.
8003 :
8004 : See GetLayers() for a C++ iterator version of this method.
8005 :
8006 : This method is the same as the C function GDALDatasetGetLayer() and the
8007 : deprecated OGR_DS_GetLayer().
8008 :
8009 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8010 :
8011 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8012 :
8013 : @see GetLayers()
8014 :
8015 : @since GDAL 3.12
8016 : */
8017 :
8018 0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8019 : {
8020 0 : return nullptr;
8021 : }
8022 :
8023 : /**
8024 : \fn GDALDataset::GetLayer(int)
8025 : \brief Fetch a layer by index.
8026 :
8027 : The returned layer remains owned by the
8028 : GDALDataset and should not be deleted by the application.
8029 :
8030 : See GetLayers() for a C++ iterator version of this method.
8031 :
8032 : This method is the same as the C function GDALDatasetGetLayer() and the
8033 : deprecated OGR_DS_GetLayer().
8034 :
8035 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8036 :
8037 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8038 :
8039 : @see GetLayers()
8040 : */
8041 :
8042 : /************************************************************************/
8043 : /* IsLayerPrivate() */
8044 : /************************************************************************/
8045 :
8046 : /**
8047 : \fn GDALDataset::IsLayerPrivate(int)
8048 : \brief Returns true if the layer at the specified index is deemed a private or
8049 : system table, or an internal detail only.
8050 :
8051 : This method is the same as the C function GDALDatasetIsLayerPrivate().
8052 :
8053 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8054 :
8055 : @return true if the layer is a private or system table.
8056 :
8057 : @since GDAL 3.4
8058 : */
8059 :
8060 950 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8061 : {
8062 950 : return false;
8063 : }
8064 :
8065 : /************************************************************************/
8066 : /* ResetReading() */
8067 : /************************************************************************/
8068 :
8069 : /**
8070 : \brief Reset feature reading to start on the first feature.
8071 :
8072 : This affects GetNextFeature().
8073 :
8074 : Depending on drivers, this may also have the side effect of calling
8075 : OGRLayer::ResetReading() on the layers of this dataset.
8076 :
8077 : This method is the same as the C function GDALDatasetResetReading().
8078 :
8079 : */
8080 7 : void GDALDataset::ResetReading()
8081 : {
8082 7 : if (!m_poPrivate)
8083 0 : return;
8084 7 : m_poPrivate->nCurrentLayerIdx = 0;
8085 7 : m_poPrivate->nLayerCount = -1;
8086 7 : m_poPrivate->poCurrentLayer = nullptr;
8087 7 : m_poPrivate->nFeatureReadInLayer = 0;
8088 7 : m_poPrivate->nFeatureReadInDataset = 0;
8089 7 : m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8090 7 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8091 : }
8092 :
8093 : /************************************************************************/
8094 : /* GDALDatasetResetReading() */
8095 : /************************************************************************/
8096 :
8097 : /**
8098 : \brief Reset feature reading to start on the first feature.
8099 :
8100 : This affects GDALDatasetGetNextFeature().
8101 :
8102 : Depending on drivers, this may also have the side effect of calling
8103 : OGR_L_ResetReading() on the layers of this dataset.
8104 :
8105 : This method is the same as the C++ method GDALDataset::ResetReading()
8106 :
8107 : @param hDS dataset handle
8108 : */
8109 14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8110 : {
8111 14 : VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8112 :
8113 14 : return GDALDataset::FromHandle(hDS)->ResetReading();
8114 : }
8115 :
8116 : /************************************************************************/
8117 : /* GetNextFeature() */
8118 : /************************************************************************/
8119 :
8120 : /**
8121 : \brief Fetch the next available feature from this dataset.
8122 :
8123 : This method is intended for the few drivers where OGRLayer::GetNextFeature()
8124 : is not efficient, but in general OGRLayer::GetNextFeature() is a more
8125 : natural API.
8126 :
8127 : See GetFeatures() for a C++ iterator version of this method.
8128 :
8129 : The returned feature becomes the responsibility of the caller to
8130 : delete with OGRFeature::DestroyFeature().
8131 :
8132 : Depending on the driver, this method may return features from layers in a
8133 : non sequential way. This is what may happen when the
8134 : ODsCRandomLayerRead capability is declared (for example for the
8135 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8136 : advised to use GDALDataset::GetNextFeature() instead of
8137 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8138 : implementation.
8139 :
8140 : The default implementation, used by most drivers, will
8141 : however iterate over each layer, and then over each feature within this
8142 : layer.
8143 :
8144 : This method takes into account spatial and attribute filters set on layers that
8145 : will be iterated upon.
8146 :
8147 : The ResetReading() method can be used to start at the beginning again.
8148 :
8149 : Depending on drivers, this may also have the side effect of calling
8150 : OGRLayer::GetNextFeature() on the layers of this dataset.
8151 :
8152 : This method is the same as the C function GDALDatasetGetNextFeature().
8153 :
8154 : @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8155 : layer to which the object belongs to, or NULL.
8156 : It is possible that the output of *ppoBelongingLayer
8157 : to be NULL despite the feature not being NULL.
8158 : @param pdfProgressPct a pointer to a double variable to receive the
8159 : percentage progress (in [0,1] range), or NULL.
8160 : On return, the pointed value might be negative if
8161 : determining the progress is not possible.
8162 : @param pfnProgress a progress callback to report progress (for
8163 : GetNextFeature() calls that might have a long
8164 : duration) and offer cancellation possibility, or NULL.
8165 : @param pProgressData user data provided to pfnProgress, or NULL
8166 : @return a feature, or NULL if no more features are available.
8167 : @see GetFeatures()
8168 : */
8169 :
8170 60 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8171 : double *pdfProgressPct,
8172 : GDALProgressFunc pfnProgress,
8173 : void *pProgressData)
8174 : {
8175 60 : if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8176 : {
8177 2 : if (ppoBelongingLayer != nullptr)
8178 2 : *ppoBelongingLayer = nullptr;
8179 2 : if (pdfProgressPct != nullptr)
8180 1 : *pdfProgressPct = 1.0;
8181 2 : if (pfnProgress != nullptr)
8182 0 : pfnProgress(1.0, "", pProgressData);
8183 2 : return nullptr;
8184 : }
8185 :
8186 58 : if (m_poPrivate->poCurrentLayer == nullptr &&
8187 8 : (pdfProgressPct != nullptr || pfnProgress != nullptr))
8188 : {
8189 1 : if (m_poPrivate->nLayerCount < 0)
8190 : {
8191 1 : m_poPrivate->nLayerCount = GetLayerCount();
8192 : }
8193 :
8194 1 : if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8195 : {
8196 1 : m_poPrivate->nTotalFeatures = 0;
8197 5 : for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8198 : {
8199 4 : OGRLayer *poLayer = GetLayer(i);
8200 8 : if (poLayer == nullptr ||
8201 4 : !poLayer->TestCapability(OLCFastFeatureCount))
8202 : {
8203 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8204 0 : break;
8205 : }
8206 4 : GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8207 4 : if (nCount < 0)
8208 : {
8209 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8210 0 : break;
8211 : }
8212 4 : m_poPrivate->nTotalFeatures += nCount;
8213 : }
8214 : }
8215 : }
8216 :
8217 : while (true)
8218 : {
8219 71 : if (m_poPrivate->poCurrentLayer == nullptr)
8220 : {
8221 44 : m_poPrivate->poCurrentLayer =
8222 22 : GetLayer(m_poPrivate->nCurrentLayerIdx);
8223 22 : if (m_poPrivate->poCurrentLayer == nullptr)
8224 : {
8225 7 : m_poPrivate->nCurrentLayerIdx = -1;
8226 7 : if (ppoBelongingLayer != nullptr)
8227 7 : *ppoBelongingLayer = nullptr;
8228 7 : if (pdfProgressPct != nullptr)
8229 1 : *pdfProgressPct = 1.0;
8230 7 : return nullptr;
8231 : }
8232 15 : m_poPrivate->poCurrentLayer->ResetReading();
8233 15 : m_poPrivate->nFeatureReadInLayer = 0;
8234 15 : if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8235 : {
8236 0 : if (m_poPrivate->poCurrentLayer->TestCapability(
8237 0 : OLCFastFeatureCount))
8238 0 : m_poPrivate->nTotalFeaturesInLayer =
8239 0 : m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8240 : else
8241 0 : m_poPrivate->nTotalFeaturesInLayer = 0;
8242 : }
8243 : }
8244 64 : OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8245 64 : if (poFeature == nullptr)
8246 : {
8247 13 : m_poPrivate->nCurrentLayerIdx++;
8248 13 : m_poPrivate->poCurrentLayer = nullptr;
8249 13 : continue;
8250 : }
8251 :
8252 51 : m_poPrivate->nFeatureReadInLayer++;
8253 51 : m_poPrivate->nFeatureReadInDataset++;
8254 51 : if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8255 : {
8256 4 : double dfPct = 0.0;
8257 4 : if (m_poPrivate->nTotalFeatures > 0)
8258 : {
8259 4 : dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8260 4 : m_poPrivate->nTotalFeatures;
8261 : }
8262 : else
8263 : {
8264 0 : dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8265 0 : m_poPrivate->nLayerCount;
8266 0 : if (m_poPrivate->nTotalFeaturesInLayer > 0)
8267 : {
8268 0 : dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8269 0 : m_poPrivate->nTotalFeaturesInLayer /
8270 0 : m_poPrivate->nLayerCount;
8271 : }
8272 : }
8273 4 : if (pdfProgressPct)
8274 4 : *pdfProgressPct = dfPct;
8275 4 : if (pfnProgress)
8276 0 : pfnProgress(dfPct, "", nullptr);
8277 : }
8278 :
8279 51 : if (ppoBelongingLayer != nullptr)
8280 51 : *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8281 51 : return poFeature;
8282 13 : }
8283 : }
8284 :
8285 : /************************************************************************/
8286 : /* GDALDatasetGetNextFeature() */
8287 : /************************************************************************/
8288 : /**
8289 : \brief Fetch the next available feature from this dataset.
8290 :
8291 : This method is intended for the few drivers where OGR_L_GetNextFeature()
8292 : is not efficient, but in general OGR_L_GetNextFeature() is a more
8293 : natural API.
8294 :
8295 : The returned feature becomes the responsibility of the caller to
8296 : delete with OGRFeature::DestroyFeature().
8297 :
8298 : Depending on the driver, this method may return features from layers in a
8299 : non sequential way. This is what may happen when the
8300 : ODsCRandomLayerRead capability is declared (for example for the
8301 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8302 : advised to use GDALDataset::GetNextFeature() instead of
8303 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8304 : implementation.
8305 :
8306 : The default implementation, used by most drivers, will
8307 : however iterate over each layer, and then over each feature within this
8308 : layer.
8309 :
8310 : This method takes into account spatial and attribute filters set on layers that
8311 : will be iterated upon.
8312 :
8313 : The ResetReading() method can be used to start at the beginning again.
8314 :
8315 : Depending on drivers, this may also have the side effect of calling
8316 : OGRLayer::GetNextFeature() on the layers of this dataset.
8317 :
8318 : This method is the same as the C++ method GDALDataset::GetNextFeature()
8319 :
8320 : @param hDS dataset handle.
8321 : @param phBelongingLayer a pointer to a OGRLayer* variable to receive the
8322 : layer to which the object belongs to, or NULL.
8323 : It is possible that the output of *ppoBelongingLayer
8324 : to be NULL despite the feature not being NULL.
8325 : @param pdfProgressPct a pointer to a double variable to receive the
8326 : percentage progress (in [0,1] range), or NULL.
8327 : On return, the pointed value might be negative if
8328 : determining the progress is not possible.
8329 : @param pfnProgress a progress callback to report progress (for
8330 : GetNextFeature() calls that might have a long
8331 : duration) and offer cancellation possibility, or NULL
8332 : @param pProgressData user data provided to pfnProgress, or NULL
8333 : @return a feature, or NULL if no more features are available.
8334 : */
8335 1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8336 : OGRLayerH *phBelongingLayer,
8337 : double *pdfProgressPct,
8338 : GDALProgressFunc pfnProgress,
8339 : void *pProgressData)
8340 : {
8341 1917 : VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8342 :
8343 3834 : return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8344 : reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8345 3834 : pfnProgress, pProgressData));
8346 : }
8347 :
8348 : /************************************************************************/
8349 : /* TestCapability() */
8350 : /************************************************************************/
8351 :
8352 : /**
8353 : \fn GDALDataset::TestCapability( const char * pszCap )
8354 : \brief Test if capability is available.
8355 :
8356 : One of the following dataset capability names can be passed into this
8357 : method, and a TRUE or FALSE value will be returned indicating whether or not
8358 : the capability is available for this object.
8359 :
8360 : <ul>
8361 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8362 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8363 : layers.<p>
8364 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8365 : datasource support CreateGeomField() just after layer creation.<p>
8366 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8367 : geometries.<p>
8368 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8369 : transactions.<p>
8370 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8371 : transactions through emulation.<p>
8372 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8373 : GetNextFeature() implementation, potentially returning features from
8374 : layers in a non sequential way.<p>
8375 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8376 : CreateFeature() on layers in a non sequential way.<p>
8377 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8378 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8379 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8380 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8381 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8382 : </ul>
8383 :
8384 : The \#define macro forms of the capability names should be used in preference
8385 : to the strings themselves to avoid misspelling.
8386 :
8387 : This method is the same as the C function GDALDatasetTestCapability() and the
8388 : deprecated OGR_DS_TestCapability().
8389 :
8390 : @param pszCap the capability to test.
8391 :
8392 : @return TRUE if capability available otherwise FALSE.
8393 : */
8394 :
8395 729 : int GDALDataset::TestCapability(const char *pszCap) const
8396 : {
8397 729 : if (EQUAL(pszCap, GDsCFastGetExtent) ||
8398 727 : EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8399 : {
8400 4 : for (auto &&poLayer : GetLayers())
8401 : {
8402 2 : if (!poLayer->TestCapability(OLCFastGetExtent))
8403 2 : return FALSE;
8404 : }
8405 2 : return TRUE;
8406 : }
8407 725 : return FALSE;
8408 : }
8409 :
8410 : /************************************************************************/
8411 : /* GDALDatasetTestCapability() */
8412 : /************************************************************************/
8413 :
8414 : /**
8415 : \brief Test if capability is available.
8416 :
8417 : One of the following dataset capability names can be passed into this
8418 : function, and a TRUE or FALSE value will be returned indicating whether or not
8419 : the capability is available for this object.
8420 :
8421 : <ul>
8422 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8423 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8424 : layers.<p>
8425 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8426 : datasource support CreateGeomField() just after layer creation.<p>
8427 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8428 : geometries.<p>
8429 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8430 : transactions.<p>
8431 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8432 : transactions through emulation.<p>
8433 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8434 : GetNextFeature() implementation, potentially returning features from
8435 : layers in a non sequential way.<p>
8436 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8437 : CreateFeature() on layers in a non sequential way.<p>
8438 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8439 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8440 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8441 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8442 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8443 : </ul>
8444 :
8445 : The \#define macro forms of the capability names should be used in preference
8446 : to the strings themselves to avoid misspelling.
8447 :
8448 : This function is the same as the C++ method GDALDataset::TestCapability()
8449 :
8450 :
8451 : @param hDS the dataset handle.
8452 : @param pszCap the capability to test.
8453 :
8454 : @return TRUE if capability available otherwise FALSE.
8455 : */
8456 127 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8457 :
8458 : {
8459 127 : VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8460 127 : VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8461 :
8462 127 : return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8463 : }
8464 :
8465 : /************************************************************************/
8466 : /* StartTransaction() */
8467 : /************************************************************************/
8468 :
8469 : /**
8470 : \fn GDALDataset::StartTransaction(int)
8471 : \brief For datasources which support transactions, StartTransaction creates a
8472 : `transaction.
8473 :
8474 : If starting the transaction fails, will return
8475 : OGRERR_FAILURE. Datasources which do not support transactions will
8476 : always return OGRERR_UNSUPPORTED_OPERATION.
8477 :
8478 : Nested transactions are not supported.
8479 :
8480 : All changes done after the start of the transaction are definitely applied in
8481 : the datasource if CommitTransaction() is called. They may be canceled by
8482 : calling RollbackTransaction() instead.
8483 :
8484 : At the time of writing, transactions only apply on vector layers.
8485 :
8486 : Datasets that support transactions will advertise the ODsCTransactions
8487 : capability. Use of transactions at dataset level is generally preferred to
8488 : transactions at layer level, whose scope is rarely limited to the layer from
8489 : which it was started.
8490 :
8491 : In case StartTransaction() fails, neither CommitTransaction() or
8492 : RollbackTransaction() should be called.
8493 :
8494 : If an error occurs after a successful StartTransaction(), the whole transaction
8495 : may or may not be implicitly canceled, depending on drivers. (e.g. the PG
8496 : driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8497 : an explicit call to RollbackTransaction() should be done to keep things
8498 : balanced.
8499 :
8500 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8501 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8502 : with significant overhead, in which case the user must explicitly allow for
8503 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8504 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8505 : ODsCTransactions).
8506 :
8507 : This function is the same as the C function GDALDatasetStartTransaction().
8508 :
8509 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8510 : transaction
8511 : mechanism is acceptable.
8512 :
8513 : @return OGRERR_NONE on success.
8514 : */
8515 :
8516 37 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8517 : {
8518 37 : return OGRERR_UNSUPPORTED_OPERATION;
8519 : }
8520 :
8521 : /************************************************************************/
8522 : /* GDALDatasetStartTransaction() */
8523 : /************************************************************************/
8524 :
8525 : /**
8526 : \brief For datasources which support transactions, StartTransaction creates a
8527 : transaction.
8528 :
8529 : If starting the transaction fails, will return
8530 : OGRERR_FAILURE. Datasources which do not support transactions will
8531 : always return OGRERR_UNSUPPORTED_OPERATION.
8532 :
8533 : Nested transactions are not supported.
8534 :
8535 : All changes done after the start of the transaction are definitely applied in
8536 : the datasource if CommitTransaction() is called. They may be canceled by
8537 : calling RollbackTransaction() instead.
8538 :
8539 : At the time of writing, transactions only apply on vector layers.
8540 :
8541 : Datasets that support transactions will advertise the ODsCTransactions
8542 : capability.
8543 : Use of transactions at dataset level is generally preferred to transactions at
8544 : layer level, whose scope is rarely limited to the layer from which it was
8545 : started.
8546 :
8547 : In case StartTransaction() fails, neither CommitTransaction() or
8548 : RollbackTransaction() should be called.
8549 :
8550 : If an error occurs after a successful StartTransaction(), the whole
8551 : transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8552 : the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8553 : error, an explicit call to RollbackTransaction() should be done to keep things
8554 : balanced.
8555 :
8556 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8557 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8558 : with significant overhead, in which case the user must explicitly allow for
8559 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8560 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8561 : ODsCTransactions).
8562 :
8563 : This function is the same as the C++ method GDALDataset::StartTransaction()
8564 :
8565 : @param hDS the dataset handle.
8566 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8567 : transaction
8568 : mechanism is acceptable.
8569 :
8570 : @return OGRERR_NONE on success.
8571 : */
8572 105 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8573 : {
8574 105 : VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8575 : OGRERR_INVALID_HANDLE);
8576 :
8577 : #ifdef OGRAPISPY_ENABLED
8578 105 : if (bOGRAPISpyEnabled)
8579 2 : OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8580 : #endif
8581 :
8582 105 : return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8583 : }
8584 :
8585 : /************************************************************************/
8586 : /* CommitTransaction() */
8587 : /************************************************************************/
8588 :
8589 : /**
8590 : \brief For datasources which support transactions, CommitTransaction commits a
8591 : transaction.
8592 :
8593 : If no transaction is active, or the commit fails, will return
8594 : OGRERR_FAILURE. Datasources which do not support transactions will
8595 : always return OGRERR_UNSUPPORTED_OPERATION.
8596 :
8597 : Depending on drivers, this may or may not abort layer sequential readings that
8598 : are active.
8599 :
8600 : This function is the same as the C function GDALDatasetCommitTransaction().
8601 :
8602 : @return OGRERR_NONE on success.
8603 : */
8604 52 : OGRErr GDALDataset::CommitTransaction()
8605 : {
8606 52 : return OGRERR_UNSUPPORTED_OPERATION;
8607 : }
8608 :
8609 : /************************************************************************/
8610 : /* GDALDatasetCommitTransaction() */
8611 : /************************************************************************/
8612 :
8613 : /**
8614 : \brief For datasources which support transactions, CommitTransaction commits a
8615 : transaction.
8616 :
8617 : If no transaction is active, or the commit fails, will return
8618 : OGRERR_FAILURE. Datasources which do not support transactions will
8619 : always return OGRERR_UNSUPPORTED_OPERATION.
8620 :
8621 : Depending on drivers, this may or may not abort layer sequential readings that
8622 : are active.
8623 :
8624 : This function is the same as the C++ method GDALDataset::CommitTransaction()
8625 :
8626 : @return OGRERR_NONE on success.
8627 : */
8628 76 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8629 : {
8630 76 : VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8631 : OGRERR_INVALID_HANDLE);
8632 :
8633 : #ifdef OGRAPISPY_ENABLED
8634 76 : if (bOGRAPISpyEnabled)
8635 2 : OGRAPISpy_Dataset_CommitTransaction(hDS);
8636 : #endif
8637 :
8638 76 : return GDALDataset::FromHandle(hDS)->CommitTransaction();
8639 : }
8640 :
8641 : /************************************************************************/
8642 : /* RollbackTransaction() */
8643 : /************************************************************************/
8644 :
8645 : /**
8646 : \brief For datasources which support transactions, RollbackTransaction will
8647 : roll back a datasource to its state before the start of the current
8648 : transaction.
8649 : If no transaction is active, or the rollback fails, will return
8650 : OGRERR_FAILURE. Datasources which do not support transactions will
8651 : always return OGRERR_UNSUPPORTED_OPERATION.
8652 :
8653 : This function is the same as the C function GDALDatasetRollbackTransaction().
8654 :
8655 : @return OGRERR_NONE on success.
8656 : */
8657 2 : OGRErr GDALDataset::RollbackTransaction()
8658 : {
8659 2 : return OGRERR_UNSUPPORTED_OPERATION;
8660 : }
8661 :
8662 : /************************************************************************/
8663 : /* GDALDatasetRollbackTransaction() */
8664 : /************************************************************************/
8665 :
8666 : /**
8667 : \brief For datasources which support transactions, RollbackTransaction will
8668 : roll back a datasource to its state before the start of the current
8669 : transaction.
8670 : If no transaction is active, or the rollback fails, will return
8671 : OGRERR_FAILURE. Datasources which do not support transactions will
8672 : always return OGRERR_UNSUPPORTED_OPERATION.
8673 :
8674 : This function is the same as the C++ method GDALDataset::RollbackTransaction().
8675 :
8676 : @return OGRERR_NONE on success.
8677 : */
8678 44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8679 : {
8680 44 : VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8681 : OGRERR_INVALID_HANDLE);
8682 :
8683 : #ifdef OGRAPISPY_ENABLED
8684 44 : if (bOGRAPISpyEnabled)
8685 2 : OGRAPISpy_Dataset_RollbackTransaction(hDS);
8686 : #endif
8687 :
8688 44 : return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8689 : }
8690 :
8691 : //! @cond Doxygen_Suppress
8692 :
8693 : /************************************************************************/
8694 : /* ShareLockWithParentDataset() */
8695 : /************************************************************************/
8696 :
8697 : /* To be used typically by the GTiff driver to link overview datasets */
8698 : /* with their main dataset, so that they share the same lock */
8699 : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
8700 : /* The parent dataset should remain alive while the this dataset is alive */
8701 :
8702 2333 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8703 : {
8704 2333 : if (m_poPrivate != nullptr)
8705 : {
8706 2333 : m_poPrivate->poParentDataset = poParentDataset;
8707 : }
8708 2333 : }
8709 :
8710 : /************************************************************************/
8711 : /* SetQueryLoggerFunc() */
8712 : /************************************************************************/
8713 :
8714 0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8715 : CPL_UNUSED void *context)
8716 : {
8717 0 : return false;
8718 : }
8719 :
8720 : /************************************************************************/
8721 : /* EnterReadWrite() */
8722 : /************************************************************************/
8723 :
8724 8018820 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8725 : {
8726 16037600 : if (m_poPrivate == nullptr ||
8727 8018820 : IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8728 11985 : return FALSE;
8729 :
8730 8006840 : if (m_poPrivate->poParentDataset)
8731 242622 : return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8732 :
8733 7764220 : if (eAccess == GA_Update)
8734 : {
8735 2211930 : if (m_poPrivate->eStateReadWriteMutex ==
8736 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8737 : {
8738 : // In case dead-lock would occur, which is not impossible,
8739 : // this can be used to prevent it, but at the risk of other
8740 : // issues.
8741 10662 : if (CPLTestBool(
8742 : CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8743 : {
8744 10662 : m_poPrivate->eStateReadWriteMutex =
8745 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8746 : }
8747 : else
8748 : {
8749 0 : m_poPrivate->eStateReadWriteMutex =
8750 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8751 : }
8752 : }
8753 2211930 : if (m_poPrivate->eStateReadWriteMutex ==
8754 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8755 : {
8756 : // There should be no race related to creating this mutex since
8757 : // it should be first created through IWriteBlock() / IRasterIO()
8758 : // and then GDALRasterBlock might call it from another thread.
8759 : #ifdef DEBUG_VERBOSE
8760 : CPLDebug("GDAL",
8761 : "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8762 : CPLGetPID(), GetDescription());
8763 : #endif
8764 1539610 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8765 :
8766 : const int nCountMutex =
8767 1539610 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8768 1539610 : if (nCountMutex == 0 && eRWFlag == GF_Read)
8769 : {
8770 521208 : CPLReleaseMutex(m_poPrivate->hMutex);
8771 1654830 : for (int i = 0; i < nBands; i++)
8772 : {
8773 1133630 : auto blockCache = papoBands[i]->poBandBlockCache;
8774 1133630 : if (blockCache)
8775 817120 : blockCache->WaitCompletionPendingTasks();
8776 : }
8777 521208 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8778 : }
8779 :
8780 1539610 : return TRUE;
8781 : }
8782 : }
8783 6224610 : return FALSE;
8784 : }
8785 :
8786 : /************************************************************************/
8787 : /* LeaveReadWrite() */
8788 : /************************************************************************/
8789 :
8790 1768570 : void GDALDataset::LeaveReadWrite()
8791 : {
8792 1768570 : if (m_poPrivate)
8793 : {
8794 1768570 : if (m_poPrivate->poParentDataset)
8795 : {
8796 228962 : m_poPrivate->poParentDataset->LeaveReadWrite();
8797 228962 : return;
8798 : }
8799 :
8800 1539610 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8801 1539610 : CPLReleaseMutex(m_poPrivate->hMutex);
8802 : #ifdef DEBUG_VERBOSE
8803 : CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8804 : CPLGetPID(), GetDescription());
8805 : #endif
8806 : }
8807 : }
8808 :
8809 : /************************************************************************/
8810 : /* InitRWLock() */
8811 : /************************************************************************/
8812 :
8813 3986570 : void GDALDataset::InitRWLock()
8814 : {
8815 3986570 : if (m_poPrivate)
8816 : {
8817 3986570 : if (m_poPrivate->poParentDataset)
8818 : {
8819 8584 : m_poPrivate->poParentDataset->InitRWLock();
8820 8584 : return;
8821 : }
8822 :
8823 3977990 : if (m_poPrivate->eStateReadWriteMutex ==
8824 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8825 : {
8826 1 : if (EnterReadWrite(GF_Write))
8827 1 : LeaveReadWrite();
8828 : }
8829 : }
8830 : }
8831 :
8832 : /************************************************************************/
8833 : /* DisableReadWriteMutex() */
8834 : /************************************************************************/
8835 :
8836 : // The mutex logic is broken in multi-threaded situations, for example
8837 : // with 2 WarpedVRT datasets being read at the same time. In that
8838 : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8839 : // to disable it.
8840 21359 : void GDALDataset::DisableReadWriteMutex()
8841 : {
8842 21359 : if (m_poPrivate)
8843 : {
8844 21359 : if (m_poPrivate->poParentDataset)
8845 : {
8846 0 : m_poPrivate->poParentDataset->DisableReadWriteMutex();
8847 0 : return;
8848 : }
8849 :
8850 21359 : m_poPrivate->eStateReadWriteMutex =
8851 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8852 : }
8853 : }
8854 :
8855 : /************************************************************************/
8856 : /* TemporarilyDropReadWriteLock() */
8857 : /************************************************************************/
8858 :
8859 3402900 : void GDALDataset::TemporarilyDropReadWriteLock()
8860 : {
8861 3402900 : if (m_poPrivate == nullptr)
8862 0 : return;
8863 :
8864 3402900 : if (m_poPrivate->poParentDataset)
8865 : {
8866 26346 : m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8867 26346 : return;
8868 : }
8869 :
8870 : #ifndef __COVERITY__
8871 3376560 : if (m_poPrivate->hMutex)
8872 : {
8873 : #ifdef DEBUG_VERBOSE
8874 : CPLDebug("GDAL",
8875 : "[Thread " CPL_FRMT_GIB "] "
8876 : "Temporarily drop RW mutex for %s",
8877 : CPLGetPID(), GetDescription());
8878 : #endif
8879 420857 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8880 : const int nCount =
8881 420857 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8882 : #ifdef DEBUG_EXTRA
8883 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8884 : #endif
8885 1269580 : for (int i = 0; i < nCount + 1; i++)
8886 : {
8887 : // The mutex is recursive
8888 848719 : CPLReleaseMutex(m_poPrivate->hMutex);
8889 : }
8890 : }
8891 : #endif
8892 : }
8893 :
8894 : /************************************************************************/
8895 : /* ReacquireReadWriteLock() */
8896 : /************************************************************************/
8897 :
8898 3402900 : void GDALDataset::ReacquireReadWriteLock()
8899 : {
8900 3402900 : if (m_poPrivate == nullptr)
8901 0 : return;
8902 :
8903 3402900 : if (m_poPrivate->poParentDataset)
8904 : {
8905 26346 : m_poPrivate->poParentDataset->ReacquireReadWriteLock();
8906 26346 : return;
8907 : }
8908 :
8909 : #ifndef __COVERITY__
8910 3376560 : if (m_poPrivate->hMutex)
8911 : {
8912 : #ifdef DEBUG_VERBOSE
8913 : CPLDebug("GDAL",
8914 : "[Thread " CPL_FRMT_GIB "] "
8915 : "Reacquire temporarily dropped RW mutex for %s",
8916 : CPLGetPID(), GetDescription());
8917 : #endif
8918 420858 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8919 : const int nCount =
8920 420858 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8921 : #ifdef DEBUG_EXTRA
8922 : CPLAssert(nCount ==
8923 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
8924 : #endif
8925 420858 : if (nCount == 0)
8926 18665 : CPLReleaseMutex(m_poPrivate->hMutex);
8927 446527 : for (int i = 0; i < nCount - 1; i++)
8928 : {
8929 : // The mutex is recursive
8930 25669 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8931 : }
8932 : }
8933 : #endif
8934 : }
8935 :
8936 : /************************************************************************/
8937 : /* AcquireMutex() */
8938 : /************************************************************************/
8939 :
8940 196 : int GDALDataset::AcquireMutex()
8941 : {
8942 196 : if (m_poPrivate == nullptr)
8943 0 : return 0;
8944 196 : if (m_poPrivate->poParentDataset)
8945 : {
8946 0 : return m_poPrivate->poParentDataset->AcquireMutex();
8947 : }
8948 :
8949 196 : return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8950 : }
8951 :
8952 : /************************************************************************/
8953 : /* ReleaseMutex() */
8954 : /************************************************************************/
8955 :
8956 196 : void GDALDataset::ReleaseMutex()
8957 : {
8958 196 : if (m_poPrivate)
8959 : {
8960 196 : if (m_poPrivate->poParentDataset)
8961 : {
8962 0 : m_poPrivate->poParentDataset->ReleaseMutex();
8963 0 : return;
8964 : }
8965 :
8966 196 : CPLReleaseMutex(m_poPrivate->hMutex);
8967 : }
8968 : }
8969 :
8970 : //! @endcond
8971 :
8972 : /************************************************************************/
8973 : /* GDALDataset::Features::Iterator::Private */
8974 : /************************************************************************/
8975 :
8976 : struct GDALDataset::Features::Iterator::Private
8977 : {
8978 : GDALDataset::FeatureLayerPair m_oPair{};
8979 : GDALDataset *m_poDS = nullptr;
8980 : bool m_bEOF = true;
8981 : };
8982 :
8983 4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
8984 4 : : m_poPrivate(new GDALDataset::Features::Iterator::Private())
8985 : {
8986 4 : m_poPrivate->m_poDS = poDS;
8987 4 : if (bStart)
8988 : {
8989 2 : poDS->ResetReading();
8990 4 : m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
8991 2 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
8992 2 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
8993 : }
8994 4 : }
8995 :
8996 : GDALDataset::Features::Iterator::~Iterator() = default;
8997 :
8998 : const GDALDataset::FeatureLayerPair &
8999 20 : GDALDataset::Features::Iterator::operator*() const
9000 : {
9001 20 : return m_poPrivate->m_oPair;
9002 : }
9003 :
9004 20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9005 : {
9006 40 : m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9007 20 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9008 20 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9009 20 : return *this;
9010 : }
9011 :
9012 22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9013 : {
9014 22 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9015 : }
9016 :
9017 : /************************************************************************/
9018 : /* GetFeatures() */
9019 : /************************************************************************/
9020 :
9021 : /** Function that return an iterable object over features in the dataset
9022 : * layer.
9023 : *
9024 : * This is a C++ iterator friendly version of GetNextFeature().
9025 : *
9026 : * Using this iterator for standard range-based loops is safe, but
9027 : * due to implementation limitations, you shouldn't try to access
9028 : * (dereference) more than one iterator step at a time, since the
9029 : * FeatureLayerPair reference which is returned is reused.
9030 : *
9031 : * Typical use is:
9032 : * \code{.cpp}
9033 : * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9034 : * {
9035 : * std::cout << "Feature of layer " <<
9036 : * oFeatureLayerPair.layer->GetName() << std::endl;
9037 : * oFeatureLayerPair.feature->DumpReadable();
9038 : * }
9039 : * \endcode
9040 : *
9041 : * @see GetNextFeature()
9042 : *
9043 : */
9044 2 : GDALDataset::Features GDALDataset::GetFeatures()
9045 : {
9046 2 : return Features(this);
9047 : }
9048 :
9049 : /************************************************************************/
9050 : /* begin() */
9051 : /************************************************************************/
9052 :
9053 : /**
9054 : \brief Return beginning of feature iterator.
9055 :
9056 : */
9057 :
9058 2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9059 : {
9060 2 : return {m_poSelf, true};
9061 : }
9062 :
9063 : /************************************************************************/
9064 : /* end() */
9065 : /************************************************************************/
9066 :
9067 : /**
9068 : \brief Return end of feature iterator.
9069 :
9070 : */
9071 :
9072 2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9073 : {
9074 2 : return {m_poSelf, false};
9075 : }
9076 :
9077 : /************************************************************************/
9078 : /* GDALDataset::Layers::Iterator::Private */
9079 : /************************************************************************/
9080 :
9081 : struct GDALDataset::Layers::Iterator::Private
9082 : {
9083 : OGRLayer *m_poLayer = nullptr;
9084 : int m_iCurLayer = 0;
9085 : int m_nLayerCount = 0;
9086 : GDALDataset *m_poDS = nullptr;
9087 : };
9088 :
9089 2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9090 : {
9091 2 : }
9092 :
9093 : // False positive of cppcheck 1.72
9094 : // cppcheck-suppress uninitMemberVar
9095 9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9096 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9097 : {
9098 9 : }
9099 :
9100 5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9101 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9102 : {
9103 5 : }
9104 :
9105 648 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9106 648 : : m_poPrivate(new Private())
9107 : {
9108 648 : m_poPrivate->m_poDS = poDS;
9109 648 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9110 648 : if (bStart)
9111 : {
9112 326 : if (m_poPrivate->m_nLayerCount)
9113 313 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9114 : }
9115 : else
9116 : {
9117 322 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9118 : }
9119 648 : }
9120 :
9121 : GDALDataset::Layers::Iterator::~Iterator() = default;
9122 :
9123 : // False positive of cppcheck 1.72
9124 : // cppcheck-suppress operatorEqVarError
9125 : GDALDataset::Layers::Iterator &
9126 1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9127 : {
9128 1 : *m_poPrivate = *oOther.m_poPrivate;
9129 1 : return *this;
9130 : }
9131 :
9132 3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9133 : GDALDataset::Layers::Iterator &&oOther) noexcept
9134 : {
9135 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9136 3 : return *this;
9137 : }
9138 :
9139 377 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9140 : {
9141 377 : return m_poPrivate->m_poLayer;
9142 : }
9143 :
9144 358 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9145 : {
9146 358 : m_poPrivate->m_iCurLayer++;
9147 358 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9148 : {
9149 70 : m_poPrivate->m_poLayer =
9150 70 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9151 : }
9152 : else
9153 : {
9154 288 : m_poPrivate->m_poLayer = nullptr;
9155 : }
9156 358 : return *this;
9157 : }
9158 :
9159 2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9160 : {
9161 2 : GDALDataset::Layers::Iterator temp = *this;
9162 2 : ++(*this);
9163 2 : return temp;
9164 : }
9165 :
9166 674 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9167 : {
9168 674 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9169 : }
9170 :
9171 : /************************************************************************/
9172 : /* GetLayers() */
9173 : /************************************************************************/
9174 :
9175 : /** Function that returns an iterable object over layers in the dataset.
9176 : *
9177 : * This is a C++ iterator friendly version of GetLayer().
9178 : *
9179 : * Typical use is:
9180 : * \code{.cpp}
9181 : * for( auto&& poLayer: poDS->GetLayers() )
9182 : * {
9183 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9184 : * }
9185 : * \endcode
9186 : *
9187 : * @see GetLayer()
9188 : *
9189 : */
9190 327 : GDALDataset::Layers GDALDataset::GetLayers()
9191 : {
9192 327 : return Layers(this);
9193 : }
9194 :
9195 : /************************************************************************/
9196 : /* begin() */
9197 : /************************************************************************/
9198 :
9199 : /**
9200 : \brief Return beginning of layer iterator.
9201 :
9202 : */
9203 :
9204 326 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9205 : {
9206 326 : return {m_poSelf, true};
9207 : }
9208 :
9209 : /************************************************************************/
9210 : /* end() */
9211 : /************************************************************************/
9212 :
9213 : /**
9214 : \brief Return end of layer iterator.
9215 :
9216 : */
9217 :
9218 322 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9219 : {
9220 322 : return {m_poSelf, false};
9221 : }
9222 :
9223 : /************************************************************************/
9224 : /* size() */
9225 : /************************************************************************/
9226 :
9227 : /**
9228 : \brief Get the number of layers in this dataset.
9229 :
9230 : @return layer count.
9231 :
9232 : */
9233 :
9234 1 : size_t GDALDataset::Layers::size() const
9235 : {
9236 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9237 : }
9238 :
9239 : /************************************************************************/
9240 : /* operator[]() */
9241 : /************************************************************************/
9242 : /**
9243 : \brief Fetch a layer by index.
9244 :
9245 : The returned layer remains owned by the
9246 : GDALDataset and should not be deleted by the application.
9247 :
9248 : @param iLayer a layer number between 0 and size()-1.
9249 :
9250 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9251 :
9252 : */
9253 :
9254 9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9255 : {
9256 9 : return m_poSelf->GetLayer(iLayer);
9257 : }
9258 :
9259 : /************************************************************************/
9260 : /* operator[]() */
9261 : /************************************************************************/
9262 : /**
9263 : \brief Fetch a layer by index.
9264 :
9265 : The returned layer remains owned by the
9266 : GDALDataset and should not be deleted by the application.
9267 :
9268 : @param iLayer a layer number between 0 and size()-1.
9269 :
9270 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9271 :
9272 : */
9273 :
9274 1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9275 : {
9276 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9277 : }
9278 :
9279 : /************************************************************************/
9280 : /* operator[]() */
9281 : /************************************************************************/
9282 : /**
9283 : \brief Fetch a layer by name.
9284 :
9285 : The returned layer remains owned by the
9286 : GDALDataset and should not be deleted by the application.
9287 :
9288 : @param pszLayerName layer name
9289 :
9290 : @return the layer, or nullptr if pszLayerName does not match with a layer
9291 :
9292 : */
9293 :
9294 1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9295 : {
9296 1 : return m_poSelf->GetLayerByName(pszLayerName);
9297 : }
9298 :
9299 : /************************************************************************/
9300 : /* GDALDataset::ConstLayers::Iterator::Private */
9301 : /************************************************************************/
9302 :
9303 : struct GDALDataset::ConstLayers::Iterator::Private
9304 : {
9305 : const OGRLayer *m_poLayer = nullptr;
9306 : int m_iCurLayer = 0;
9307 : int m_nLayerCount = 0;
9308 : const GDALDataset *m_poDS = nullptr;
9309 : };
9310 :
9311 2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9312 : {
9313 2 : }
9314 :
9315 : // False positive of cppcheck 1.72
9316 : // cppcheck-suppress uninitMemberVar
9317 9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9318 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9319 : {
9320 9 : }
9321 :
9322 5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9323 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9324 : {
9325 5 : }
9326 :
9327 35126 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9328 35126 : bool bStart)
9329 35126 : : m_poPrivate(new Private())
9330 : {
9331 35126 : m_poPrivate->m_poDS = poDS;
9332 35126 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9333 35126 : if (bStart)
9334 : {
9335 17565 : if (m_poPrivate->m_nLayerCount)
9336 218 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9337 : }
9338 : else
9339 : {
9340 17561 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9341 : }
9342 35126 : }
9343 :
9344 : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9345 :
9346 : // False positive of cppcheck 1.72
9347 : // cppcheck-suppress operatorEqVarError
9348 : GDALDataset::ConstLayers::Iterator &
9349 1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9350 : {
9351 1 : *m_poPrivate = *oOther.m_poPrivate;
9352 1 : return *this;
9353 : }
9354 :
9355 : GDALDataset::ConstLayers::Iterator &
9356 3 : GDALDataset::ConstLayers::Iterator::operator=(
9357 : GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9358 : {
9359 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9360 3 : return *this;
9361 : }
9362 :
9363 16176 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9364 : {
9365 16176 : return m_poPrivate->m_poLayer;
9366 : }
9367 :
9368 : GDALDataset::ConstLayers::Iterator &
9369 16171 : GDALDataset::ConstLayers::Iterator::operator++()
9370 : {
9371 16171 : m_poPrivate->m_iCurLayer++;
9372 16171 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9373 : {
9374 15964 : m_poPrivate->m_poLayer =
9375 15964 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9376 : }
9377 : else
9378 : {
9379 207 : m_poPrivate->m_poLayer = nullptr;
9380 : }
9381 16171 : return *this;
9382 : }
9383 :
9384 : GDALDataset::ConstLayers::Iterator
9385 2 : GDALDataset::ConstLayers::Iterator::operator++(int)
9386 : {
9387 2 : GDALDataset::ConstLayers::Iterator temp = *this;
9388 2 : ++(*this);
9389 2 : return temp;
9390 : }
9391 :
9392 33726 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9393 : {
9394 33726 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9395 : }
9396 :
9397 : /************************************************************************/
9398 : /* GetLayers() */
9399 : /************************************************************************/
9400 :
9401 : /** Function that returns an iterable object over layers in the dataset.
9402 : *
9403 : * This is a C++ iterator friendly version of GetLayer().
9404 : *
9405 : * Typical use is:
9406 : * \code{.cpp}
9407 : * for( auto&& poLayer: poDS->GetLayers() )
9408 : * {
9409 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9410 : * }
9411 : * \endcode
9412 : *
9413 : * @see GetLayer()
9414 : *
9415 : * @since GDAL 3.12
9416 : */
9417 17566 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
9418 : {
9419 17566 : return ConstLayers(this);
9420 : }
9421 :
9422 : /************************************************************************/
9423 : /* begin() */
9424 : /************************************************************************/
9425 :
9426 : /**
9427 : \brief Return beginning of layer iterator.
9428 :
9429 : @since GDAL 3.12
9430 : */
9431 :
9432 17565 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9433 : {
9434 17565 : return {m_poSelf, true};
9435 : }
9436 :
9437 : /************************************************************************/
9438 : /* end() */
9439 : /************************************************************************/
9440 :
9441 : /**
9442 : \brief Return end of layer iterator.
9443 :
9444 : @since GDAL 3.12
9445 : */
9446 :
9447 17561 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9448 : {
9449 17561 : return {m_poSelf, false};
9450 : }
9451 :
9452 : /************************************************************************/
9453 : /* size() */
9454 : /************************************************************************/
9455 :
9456 : /**
9457 : \brief Get the number of layers in this dataset.
9458 :
9459 : @return layer count.
9460 :
9461 : @since GDAL 3.12
9462 : */
9463 :
9464 1 : size_t GDALDataset::ConstLayers::size() const
9465 : {
9466 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9467 : }
9468 :
9469 : /************************************************************************/
9470 : /* operator[]() */
9471 : /************************************************************************/
9472 : /**
9473 : \brief Fetch a layer by index.
9474 :
9475 : The returned layer remains owned by the
9476 : GDALDataset and should not be deleted by the application.
9477 :
9478 : @param iLayer a layer number between 0 and size()-1.
9479 :
9480 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9481 :
9482 : @since GDAL 3.12
9483 : */
9484 :
9485 9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9486 : {
9487 9 : return m_poSelf->GetLayer(iLayer);
9488 : }
9489 :
9490 : /************************************************************************/
9491 : /* operator[]() */
9492 : /************************************************************************/
9493 : /**
9494 : \brief Fetch a layer by index.
9495 :
9496 : The returned layer remains owned by the
9497 : GDALDataset and should not be deleted by the application.
9498 :
9499 : @param iLayer a layer number between 0 and size()-1.
9500 :
9501 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9502 :
9503 : @since GDAL 3.12
9504 : */
9505 :
9506 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9507 : {
9508 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9509 : }
9510 :
9511 : /************************************************************************/
9512 : /* operator[]() */
9513 : /************************************************************************/
9514 : /**
9515 : \brief Fetch a layer by name.
9516 :
9517 : The returned layer remains owned by the
9518 : GDALDataset and should not be deleted by the application.
9519 :
9520 : @param pszLayerName layer name
9521 :
9522 : @return the layer, or nullptr if pszLayerName does not match with a layer
9523 :
9524 : @since GDAL 3.12
9525 : */
9526 :
9527 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9528 : {
9529 1 : return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9530 : }
9531 :
9532 : /************************************************************************/
9533 : /* GDALDataset::Bands::Iterator::Private */
9534 : /************************************************************************/
9535 :
9536 : struct GDALDataset::Bands::Iterator::Private
9537 : {
9538 : GDALRasterBand *m_poBand = nullptr;
9539 : int m_iCurBand = 0;
9540 : int m_nBandCount = 0;
9541 : GDALDataset *m_poDS = nullptr;
9542 : };
9543 :
9544 6 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9545 6 : : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9546 : {
9547 6 : m_poPrivate->m_poDS = poDS;
9548 6 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9549 6 : if (bStart)
9550 : {
9551 3 : if (m_poPrivate->m_nBandCount)
9552 3 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9553 : }
9554 : else
9555 : {
9556 3 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9557 : }
9558 6 : }
9559 :
9560 : GDALDataset::Bands::Iterator::~Iterator() = default;
9561 :
9562 5 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9563 : {
9564 5 : return m_poPrivate->m_poBand;
9565 : }
9566 :
9567 3 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9568 : {
9569 3 : m_poPrivate->m_iCurBand++;
9570 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9571 : {
9572 2 : m_poPrivate->m_poBand =
9573 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9574 : }
9575 : else
9576 : {
9577 1 : m_poPrivate->m_poBand = nullptr;
9578 : }
9579 3 : return *this;
9580 : }
9581 :
9582 6 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9583 : {
9584 6 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9585 : }
9586 :
9587 : /************************************************************************/
9588 : /* GetBands() */
9589 : /************************************************************************/
9590 :
9591 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9592 : *
9593 : * This is a C++ iterator friendly version of GetRasterBand().
9594 : *
9595 : * Typical use is:
9596 : * \code{.cpp}
9597 : * for( auto&& poBand: poDS->GetBands() )
9598 : * {
9599 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9600 : * }
9601 : * \endcode
9602 : *
9603 : * @see GetRasterBand()
9604 : *
9605 : */
9606 7 : GDALDataset::Bands GDALDataset::GetBands()
9607 : {
9608 7 : return Bands(this);
9609 : }
9610 :
9611 : /************************************************************************/
9612 : /* begin() */
9613 : /************************************************************************/
9614 :
9615 : /**
9616 : \brief Return beginning of band iterator.
9617 :
9618 : */
9619 :
9620 3 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9621 : {
9622 3 : return {m_poSelf, true};
9623 : }
9624 :
9625 : /************************************************************************/
9626 : /* end() */
9627 : /************************************************************************/
9628 :
9629 : /**
9630 : \brief Return end of band iterator.
9631 :
9632 : */
9633 :
9634 3 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9635 : {
9636 3 : return {m_poSelf, false};
9637 : }
9638 :
9639 : /************************************************************************/
9640 : /* size() */
9641 : /************************************************************************/
9642 :
9643 : /**
9644 : \brief Get the number of raster bands in this dataset.
9645 :
9646 : @return raster band count.
9647 :
9648 : */
9649 :
9650 2 : size_t GDALDataset::Bands::size() const
9651 : {
9652 2 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9653 : }
9654 :
9655 : /************************************************************************/
9656 : /* operator[]() */
9657 : /************************************************************************/
9658 : /**
9659 : \brief Fetch a raster band by index.
9660 :
9661 : The returned band remains owned by the
9662 : GDALDataset and should not be deleted by the application.
9663 :
9664 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9665 : consistent with the conventions of C/C++, i.e. starting at 0.
9666 :
9667 : @param iBand a band index between 0 and size()-1.
9668 :
9669 : @return the band, or nullptr if iBand is out of range or an error occurs.
9670 :
9671 : */
9672 :
9673 1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9674 : {
9675 1 : return m_poSelf->GetRasterBand(1 + iBand);
9676 : }
9677 :
9678 : /************************************************************************/
9679 : /* operator[]() */
9680 : /************************************************************************/
9681 :
9682 : /**
9683 : \brief Fetch a raster band by index.
9684 :
9685 : The returned band remains owned by the
9686 : GDALDataset and should not be deleted by the application.
9687 :
9688 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9689 : consistent with the conventions of C/C++, i.e. starting at 0.
9690 :
9691 : @param iBand a band index between 0 and size()-1.
9692 :
9693 : @return the band, or nullptr if iBand is out of range or an error occurs.
9694 :
9695 : */
9696 :
9697 1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9698 : {
9699 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9700 : }
9701 :
9702 : /************************************************************************/
9703 : /* GDALDataset::ConstBands::Iterator::Private */
9704 : /************************************************************************/
9705 :
9706 : struct GDALDataset::ConstBands::Iterator::Private
9707 : {
9708 : const GDALRasterBand *m_poBand = nullptr;
9709 : int m_iCurBand = 0;
9710 : int m_nBandCount = 0;
9711 : const GDALDataset *m_poDS = nullptr;
9712 : };
9713 :
9714 2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9715 2 : bool bStart)
9716 2 : : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9717 : {
9718 2 : m_poPrivate->m_poDS = poDS;
9719 2 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9720 2 : if (bStart)
9721 : {
9722 1 : if (m_poPrivate->m_nBandCount)
9723 1 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9724 : }
9725 : else
9726 : {
9727 1 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9728 : }
9729 2 : }
9730 :
9731 : GDALDataset::ConstBands::Iterator::~Iterator() = default;
9732 :
9733 3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9734 : {
9735 3 : return m_poPrivate->m_poBand;
9736 : }
9737 :
9738 : GDALDataset::ConstBands::Iterator &
9739 3 : GDALDataset::ConstBands::Iterator::operator++()
9740 : {
9741 3 : m_poPrivate->m_iCurBand++;
9742 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9743 : {
9744 2 : m_poPrivate->m_poBand =
9745 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9746 : }
9747 : else
9748 : {
9749 1 : m_poPrivate->m_poBand = nullptr;
9750 : }
9751 3 : return *this;
9752 : }
9753 :
9754 4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9755 : {
9756 4 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9757 : }
9758 :
9759 : /************************************************************************/
9760 : /* GetBands() */
9761 : /************************************************************************/
9762 :
9763 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9764 : *
9765 : * This is a C++ iterator friendly version of GetRasterBand().
9766 : *
9767 : * Typical use is:
9768 : * \code{.cpp}
9769 : * for( const auto* poBand: poDS->GetConstBands() )
9770 : * {
9771 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9772 : * }
9773 : * \endcode
9774 : *
9775 : * @see GetRasterBand()
9776 : *
9777 : * @since GDAL 3.12
9778 : */
9779 4 : GDALDataset::ConstBands GDALDataset::GetBands() const
9780 : {
9781 4 : return ConstBands(this);
9782 : }
9783 :
9784 : /************************************************************************/
9785 : /* begin() */
9786 : /************************************************************************/
9787 :
9788 : /**
9789 : \brief Return beginning of band iterator.
9790 :
9791 : @since GDAL 3.12
9792 : */
9793 :
9794 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9795 : {
9796 1 : return {m_poSelf, true};
9797 : }
9798 :
9799 : /************************************************************************/
9800 : /* end() */
9801 : /************************************************************************/
9802 :
9803 : /**
9804 : \brief Return end of band iterator.
9805 :
9806 : @since GDAL 3.12
9807 : */
9808 :
9809 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9810 : {
9811 1 : return {m_poSelf, false};
9812 : }
9813 :
9814 : /************************************************************************/
9815 : /* size() */
9816 : /************************************************************************/
9817 :
9818 : /**
9819 : \brief Get the number of raster bands in this dataset.
9820 :
9821 : @return raster band count.
9822 :
9823 : @since GDAL 3.12
9824 : */
9825 :
9826 1 : size_t GDALDataset::ConstBands::size() const
9827 : {
9828 1 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9829 : }
9830 :
9831 : /************************************************************************/
9832 : /* operator[]() */
9833 : /************************************************************************/
9834 : /**
9835 : \brief Fetch a raster band by index.
9836 :
9837 : The returned band remains owned by the
9838 : GDALDataset and should not be deleted by the application.
9839 :
9840 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9841 : consistent with the conventions of C/C++, i.e. starting at 0.
9842 :
9843 : @param iBand a band index between 0 and size()-1.
9844 :
9845 : @return the band, or nullptr if iBand is out of range or an error occurs.
9846 :
9847 : @since GDAL 3.12
9848 : */
9849 :
9850 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9851 : {
9852 1 : return m_poSelf->GetRasterBand(1 + iBand);
9853 : }
9854 :
9855 : /************************************************************************/
9856 : /* operator[]() */
9857 : /************************************************************************/
9858 :
9859 : /**
9860 : \brief Fetch a raster band by index.
9861 :
9862 : The returned band remains owned by the
9863 : GDALDataset and should not be deleted by the application.
9864 :
9865 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9866 : consistent with the conventions of C/C++, i.e. starting at 0.
9867 :
9868 : @param iBand a band index between 0 and size()-1.
9869 :
9870 : @return the band, or nullptr if iBand is out of range or an error occurs.
9871 :
9872 : @since GDAL 3.12
9873 : */
9874 :
9875 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9876 : {
9877 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9878 : }
9879 :
9880 : /************************************************************************/
9881 : /* GetRootGroup() */
9882 : /************************************************************************/
9883 :
9884 : /**
9885 : \brief Return the root GDALGroup of this dataset.
9886 :
9887 : Only valid for multidimensional datasets.
9888 :
9889 : This is the same as the C function GDALDatasetGetRootGroup().
9890 :
9891 : @since GDAL 3.1
9892 : */
9893 :
9894 2875 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
9895 : {
9896 2875 : return nullptr;
9897 : }
9898 :
9899 : /************************************************************************/
9900 : /* GetRawBinaryLayout() */
9901 : /************************************************************************/
9902 :
9903 : //! @cond Doxygen_Suppress
9904 : /**
9905 : \brief Return the layout of a dataset that can be considered as a raw binary
9906 : format.
9907 :
9908 : @param sLayout Structure that will be set if the dataset is a raw binary one.
9909 : @return true if the dataset is a raw binary one.
9910 : @since GDAL 3.1
9911 : */
9912 :
9913 0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
9914 : {
9915 0 : CPL_IGNORE_RET_VAL(sLayout);
9916 0 : return false;
9917 : }
9918 :
9919 : //! @endcond
9920 :
9921 : /************************************************************************/
9922 : /* ClearStatistics() */
9923 : /************************************************************************/
9924 :
9925 : /**
9926 : \brief Clear statistics
9927 :
9928 : Only implemented for now in PAM supported datasets
9929 :
9930 : This is the same as the C function GDALDatasetClearStatistics().
9931 :
9932 : @since GDAL 3.2
9933 : */
9934 :
9935 11 : void GDALDataset::ClearStatistics()
9936 : {
9937 22 : auto poRootGroup = GetRootGroup();
9938 11 : if (poRootGroup)
9939 1 : poRootGroup->ClearStatistics();
9940 11 : }
9941 :
9942 : /************************************************************************/
9943 : /* GDALDatasetClearStatistics() */
9944 : /************************************************************************/
9945 :
9946 : /**
9947 : \brief Clear statistics
9948 :
9949 : This is the same as the C++ method GDALDataset::ClearStatistics().
9950 :
9951 : @since GDAL 3.2
9952 : */
9953 :
9954 2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
9955 : {
9956 2 : VALIDATE_POINTER0(hDS, __func__);
9957 2 : GDALDataset::FromHandle(hDS)->ClearStatistics();
9958 : }
9959 :
9960 : /************************************************************************/
9961 : /* GetFieldDomainNames() */
9962 : /************************************************************************/
9963 :
9964 : /** Returns a list of the names of all field domains stored in the dataset.
9965 : *
9966 : * @note The default implementation assumes that drivers fully populate
9967 : * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
9968 : * then a specialized implementation of GetFieldDomainNames() must be
9969 : * implemented.
9970 : *
9971 : * @param papszOptions Driver specific options determining how attributes
9972 : * should be retrieved. Pass nullptr for default behavior.
9973 : *
9974 : * @return list of field domain names
9975 : * @since GDAL 3.5
9976 : */
9977 : std::vector<std::string>
9978 46 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
9979 : {
9980 :
9981 46 : std::vector<std::string> names;
9982 46 : names.reserve(m_oMapFieldDomains.size());
9983 58 : for (const auto &it : m_oMapFieldDomains)
9984 : {
9985 12 : names.emplace_back(it.first);
9986 : }
9987 46 : return names;
9988 : }
9989 :
9990 : /************************************************************************/
9991 : /* GDALDatasetGetFieldDomainNames() */
9992 : /************************************************************************/
9993 :
9994 : /** Returns a list of the names of all field domains stored in the dataset.
9995 : *
9996 : * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
9997 : *
9998 : * @param hDS Dataset handle.
9999 : * @param papszOptions Driver specific options determining how attributes
10000 : * should be retrieved. Pass nullptr for default behavior.
10001 : *
10002 : * @return list of field domain names, to be freed with CSLDestroy()
10003 : * @since GDAL 3.5
10004 : */
10005 34 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10006 : CSLConstList papszOptions)
10007 : {
10008 34 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10009 : auto names =
10010 68 : GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10011 68 : CPLStringList res;
10012 154 : for (const auto &name : names)
10013 : {
10014 120 : res.AddString(name.c_str());
10015 : }
10016 34 : return res.StealList();
10017 : }
10018 :
10019 : /************************************************************************/
10020 : /* GetFieldDomain() */
10021 : /************************************************************************/
10022 :
10023 : /** Get a field domain from its name.
10024 : *
10025 : * @return the field domain, or nullptr if not found.
10026 : * @since GDAL 3.3
10027 : */
10028 323 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10029 : {
10030 323 : const auto iter = m_oMapFieldDomains.find(name);
10031 323 : if (iter == m_oMapFieldDomains.end())
10032 151 : return nullptr;
10033 172 : return iter->second.get();
10034 : }
10035 :
10036 : /************************************************************************/
10037 : /* GDALDatasetGetFieldDomain() */
10038 : /************************************************************************/
10039 :
10040 : /** Get a field domain from its name.
10041 : *
10042 : * This is the same as the C++ method GDALDataset::GetFieldDomain().
10043 : *
10044 : * @param hDS Dataset handle.
10045 : * @param pszName Name of field domain.
10046 : * @return the field domain (ownership remains to the dataset), or nullptr if
10047 : * not found.
10048 : * @since GDAL 3.3
10049 : */
10050 130 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10051 : {
10052 130 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10053 130 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10054 130 : return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10055 130 : GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10056 : }
10057 :
10058 : /************************************************************************/
10059 : /* AddFieldDomain() */
10060 : /************************************************************************/
10061 :
10062 : /** Add a field domain to the dataset.
10063 : *
10064 : * Only a few drivers will support this operation, and some of them might only
10065 : * support it only for some types of field domains.
10066 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10067 : * support this operation. A dataset having at least some support for this
10068 : * operation should report the ODsCAddFieldDomain dataset capability.
10069 : *
10070 : * Anticipated failures will not be emitted through the CPLError()
10071 : * infrastructure, but will be reported in the failureReason output parameter.
10072 : *
10073 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10074 : * default implementation of GetFieldDomainNames() to work correctly, or
10075 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10076 : * implemented.
10077 : *
10078 : * @param domain The domain definition.
10079 : * @param failureReason Output parameter. Will contain an error message if
10080 : * an error occurs.
10081 : * @return true in case of success.
10082 : * @since GDAL 3.3
10083 : */
10084 0 : bool GDALDataset::AddFieldDomain(
10085 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10086 : std::string &failureReason)
10087 : {
10088 0 : failureReason = "AddFieldDomain not supported by this driver";
10089 0 : return false;
10090 : }
10091 :
10092 : /************************************************************************/
10093 : /* GDALDatasetAddFieldDomain() */
10094 : /************************************************************************/
10095 :
10096 : /** Add a field domain to the dataset.
10097 : *
10098 : * Only a few drivers will support this operation, and some of them might only
10099 : * support it only for some types of field domains.
10100 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10101 : * support this operation. A dataset having at least some support for this
10102 : * operation should report the ODsCAddFieldDomain dataset capability.
10103 : *
10104 : * Anticipated failures will not be emitted through the CPLError()
10105 : * infrastructure, but will be reported in the ppszFailureReason output
10106 : * parameter.
10107 : *
10108 : * @param hDS Dataset handle.
10109 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10110 : * the passed object is copied.
10111 : * @param ppszFailureReason Output parameter. Will contain an error message if
10112 : * an error occurs (*ppszFailureReason to be freed
10113 : * with CPLFree). May be NULL.
10114 : * @return true in case of success.
10115 : * @since GDAL 3.3
10116 : */
10117 37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10118 : char **ppszFailureReason)
10119 : {
10120 37 : VALIDATE_POINTER1(hDS, __func__, false);
10121 37 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10122 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10123 74 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10124 37 : if (poDomain == nullptr)
10125 0 : return false;
10126 37 : std::string failureReason;
10127 74 : const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10128 37 : std::move(poDomain), failureReason);
10129 37 : if (ppszFailureReason)
10130 : {
10131 37 : *ppszFailureReason =
10132 37 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10133 : }
10134 37 : return bRet;
10135 : }
10136 :
10137 : /************************************************************************/
10138 : /* DeleteFieldDomain() */
10139 : /************************************************************************/
10140 :
10141 : /** Removes a field domain from the dataset.
10142 : *
10143 : * Only a few drivers will support this operation.
10144 : *
10145 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10146 : * support this operation. A dataset having at least some support for this
10147 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10148 : *
10149 : * Anticipated failures will not be emitted through the CPLError()
10150 : * infrastructure, but will be reported in the failureReason output parameter.
10151 : *
10152 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10153 : * default implementation of GetFieldDomainNames() to work correctly, or
10154 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10155 : * implemented.
10156 : *
10157 : * @param name The domain name.
10158 : * @param failureReason Output parameter. Will contain an error message if
10159 : * an error occurs.
10160 : * @return true in case of success.
10161 : * @since GDAL 3.5
10162 : */
10163 0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10164 : std::string &failureReason)
10165 : {
10166 0 : failureReason = "DeleteFieldDomain not supported by this driver";
10167 0 : return false;
10168 : }
10169 :
10170 : /************************************************************************/
10171 : /* GDALDatasetDeleteFieldDomain() */
10172 : /************************************************************************/
10173 :
10174 : /** Removes a field domain from the dataset.
10175 : *
10176 : * Only a few drivers will support this operation.
10177 : *
10178 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10179 : * support this operation. A dataset having at least some support for this
10180 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10181 : *
10182 : * Anticipated failures will not be emitted through the CPLError()
10183 : * infrastructure, but will be reported in the ppszFailureReason output
10184 : * parameter.
10185 : *
10186 : * @param hDS Dataset handle.
10187 : * @param pszName The domain name.
10188 : * @param ppszFailureReason Output parameter. Will contain an error message if
10189 : * an error occurs (*ppszFailureReason to be freed
10190 : * with CPLFree). May be NULL.
10191 : * @return true in case of success.
10192 : * @since GDAL 3.3
10193 : */
10194 25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10195 : char **ppszFailureReason)
10196 : {
10197 25 : VALIDATE_POINTER1(hDS, __func__, false);
10198 25 : VALIDATE_POINTER1(pszName, __func__, false);
10199 25 : std::string failureReason;
10200 : const bool bRet =
10201 25 : GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10202 25 : if (ppszFailureReason)
10203 : {
10204 0 : *ppszFailureReason =
10205 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10206 : }
10207 25 : return bRet;
10208 : }
10209 :
10210 : /************************************************************************/
10211 : /* UpdateFieldDomain() */
10212 : /************************************************************************/
10213 :
10214 : /** Updates an existing field domain by replacing its definition.
10215 : *
10216 : * The existing field domain with matching name will be replaced.
10217 : *
10218 : * Only a few drivers will support this operation, and some of them might only
10219 : * support it only for some types of field domains.
10220 : * At the time of writing (GDAL 3.5), only the Memory driver
10221 : * supports this operation. A dataset having at least some support for this
10222 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10223 : *
10224 : * Anticipated failures will not be emitted through the CPLError()
10225 : * infrastructure, but will be reported in the failureReason output parameter.
10226 : *
10227 : * @param domain The domain definition.
10228 : * @param failureReason Output parameter. Will contain an error message if
10229 : * an error occurs.
10230 : * @return true in case of success.
10231 : * @since GDAL 3.5
10232 : */
10233 0 : bool GDALDataset::UpdateFieldDomain(
10234 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10235 : std::string &failureReason)
10236 : {
10237 0 : failureReason = "UpdateFieldDomain not supported by this driver";
10238 0 : return false;
10239 : }
10240 :
10241 : /************************************************************************/
10242 : /* GDALDatasetUpdateFieldDomain() */
10243 : /************************************************************************/
10244 :
10245 : /** Updates an existing field domain by replacing its definition.
10246 : *
10247 : * The existing field domain with matching name will be replaced.
10248 : *
10249 : * Only a few drivers will support this operation, and some of them might only
10250 : * support it only for some types of field domains.
10251 : * At the time of writing (GDAL 3.5), only the Memory driver
10252 : * supports this operation. A dataset having at least some support for this
10253 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10254 : *
10255 : * Anticipated failures will not be emitted through the CPLError()
10256 : * infrastructure, but will be reported in the failureReason output parameter.
10257 : *
10258 : * @param hDS Dataset handle.
10259 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10260 : * the passed object is copied.
10261 : * @param ppszFailureReason Output parameter. Will contain an error message if
10262 : * an error occurs (*ppszFailureReason to be freed
10263 : * with CPLFree). May be NULL.
10264 : * @return true in case of success.
10265 : * @since GDAL 3.5
10266 : */
10267 7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10268 : OGRFieldDomainH hFieldDomain,
10269 : char **ppszFailureReason)
10270 : {
10271 7 : VALIDATE_POINTER1(hDS, __func__, false);
10272 7 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10273 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10274 14 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10275 7 : if (poDomain == nullptr)
10276 0 : return false;
10277 7 : std::string failureReason;
10278 14 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10279 7 : std::move(poDomain), failureReason);
10280 7 : if (ppszFailureReason)
10281 : {
10282 0 : *ppszFailureReason =
10283 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10284 : }
10285 7 : return bRet;
10286 : }
10287 :
10288 : /************************************************************************/
10289 : /* GetRelationshipNames() */
10290 : /************************************************************************/
10291 :
10292 : /** Returns a list of the names of all relationships stored in the dataset.
10293 : *
10294 : * @param papszOptions Driver specific options determining how relationships
10295 : * should be retrieved. Pass nullptr for default behavior.
10296 : *
10297 : * @return list of relationship names
10298 : * @since GDAL 3.6
10299 : */
10300 : std::vector<std::string>
10301 185 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10302 : {
10303 185 : return {};
10304 : }
10305 :
10306 : /************************************************************************/
10307 : /* GDALDatasetGetRelationshipNames() */
10308 : /************************************************************************/
10309 :
10310 : /** Returns a list of the names of all relationships stored in the dataset.
10311 : *
10312 : * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10313 : *
10314 : * @param hDS Dataset handle.
10315 : * @param papszOptions Driver specific options determining how relationships
10316 : * should be retrieved. Pass nullptr for default behavior.
10317 : *
10318 : * @return list of relationship names, to be freed with CSLDestroy()
10319 : * @since GDAL 3.6
10320 : */
10321 46 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10322 : CSLConstList papszOptions)
10323 : {
10324 46 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10325 : auto names =
10326 92 : GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10327 92 : CPLStringList res;
10328 146 : for (const auto &name : names)
10329 : {
10330 100 : res.AddString(name.c_str());
10331 : }
10332 46 : return res.StealList();
10333 : }
10334 :
10335 : /************************************************************************/
10336 : /* GetRelationship() */
10337 : /************************************************************************/
10338 :
10339 : /** Get a relationship from its name.
10340 : *
10341 : * @return the relationship, or nullptr if not found.
10342 : * @since GDAL 3.6
10343 : */
10344 : const GDALRelationship *
10345 0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10346 : {
10347 0 : return nullptr;
10348 : }
10349 :
10350 : /************************************************************************/
10351 : /* GDALDatasetGetRelationship() */
10352 : /************************************************************************/
10353 :
10354 : /** Get a relationship from its name.
10355 : *
10356 : * This is the same as the C++ method GDALDataset::GetRelationship().
10357 : *
10358 : * @param hDS Dataset handle.
10359 : * @param pszName Name of relationship.
10360 : * @return the relationship (ownership remains to the dataset), or nullptr if
10361 : * not found.
10362 : * @since GDAL 3.6
10363 : */
10364 52 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10365 : const char *pszName)
10366 : {
10367 52 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10368 52 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10369 52 : return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10370 52 : GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10371 : }
10372 :
10373 : /************************************************************************/
10374 : /* AddRelationship() */
10375 : /************************************************************************/
10376 :
10377 : /** Add a relationship to the dataset.
10378 : *
10379 : * Only a few drivers will support this operation, and some of them might only
10380 : * support it only for some types of relationships.
10381 : *
10382 : * A dataset having at least some support for this
10383 : * operation should report the GDsCAddRelationship dataset capability.
10384 : *
10385 : * Anticipated failures will not be emitted through the CPLError()
10386 : * infrastructure, but will be reported in the failureReason output parameter.
10387 : *
10388 : * When adding a many-to-many relationship
10389 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10390 : * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10391 : * the driver to create an appropriately named and structured mapping table.
10392 : * Some dataset formats require particular naming conventions and field
10393 : * structures for the mapping table, and delegating the construction of the
10394 : * mapping table to the driver will avoid these pitfalls.
10395 : *
10396 : * @param relationship The relationship definition.
10397 : * @param failureReason Output parameter. Will contain an error message if
10398 : * an error occurs.
10399 : * @return true in case of success.
10400 : * @since GDAL 3.6
10401 : */
10402 0 : bool GDALDataset::AddRelationship(
10403 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10404 : std::string &failureReason)
10405 : {
10406 0 : failureReason = "AddRelationship not supported by this driver";
10407 0 : return false;
10408 : }
10409 :
10410 : /************************************************************************/
10411 : /* GDALDatasetAddRelationship() */
10412 : /************************************************************************/
10413 :
10414 : /** Add a relationship to the dataset.
10415 : *
10416 : * Only a few drivers will support this operation, and some of them might only
10417 : * support it only for some types of relationships.
10418 : *
10419 : * A dataset having at least some support for this
10420 : * operation should report the GDsCAddRelationship dataset capability.
10421 : *
10422 : * Anticipated failures will not be emitted through the CPLError()
10423 : * infrastructure, but will be reported in the failureReason output parameter.
10424 : *
10425 : * When adding a many-to-many relationship
10426 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10427 : * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10428 : * driver to create an appropriately named and structured mapping table. Some
10429 : * dataset formats require particular naming conventions and field structures
10430 : * for the mapping table, and delegating the construction of the mapping table
10431 : * to the driver will avoid these pitfalls.
10432 : *
10433 : * @param hDS Dataset handle.
10434 : * @param hRelationship The relationship definition. Contrary to the C++
10435 : * version, the passed object is copied.
10436 : * @param ppszFailureReason Output parameter. Will contain an error message if
10437 : * an error occurs (*ppszFailureReason to be freed
10438 : * with CPLFree). May be NULL.
10439 : * @return true in case of success.
10440 : * @since GDAL 3.6
10441 : */
10442 42 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10443 : GDALRelationshipH hRelationship,
10444 : char **ppszFailureReason)
10445 : {
10446 42 : VALIDATE_POINTER1(hDS, __func__, false);
10447 42 : VALIDATE_POINTER1(hRelationship, __func__, false);
10448 : std::unique_ptr<GDALRelationship> poRelationship(
10449 84 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10450 42 : std::string failureReason;
10451 84 : const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10452 42 : std::move(poRelationship), failureReason);
10453 42 : if (ppszFailureReason)
10454 : {
10455 0 : *ppszFailureReason =
10456 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10457 : }
10458 42 : return bRet;
10459 : }
10460 :
10461 : /************************************************************************/
10462 : /* DeleteRelationship() */
10463 : /************************************************************************/
10464 :
10465 : /** Removes a relationship from the dataset.
10466 : *
10467 : * Only a few drivers will support this operation.
10468 : *
10469 : * A dataset having at least some support for this
10470 : * operation should report the GDsCDeleteRelationship dataset capability.
10471 : *
10472 : * Anticipated failures will not be emitted through the CPLError()
10473 : * infrastructure, but will be reported in the failureReason output parameter.
10474 : *
10475 : * @param name The relationship name.
10476 : * @param failureReason Output parameter. Will contain an error message if
10477 : * an error occurs.
10478 : * @return true in case of success.
10479 : * @since GDAL 3.6
10480 : */
10481 0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10482 : std::string &failureReason)
10483 : {
10484 0 : failureReason = "DeleteRelationship not supported by this driver";
10485 0 : return false;
10486 : }
10487 :
10488 : /************************************************************************/
10489 : /* GDALDatasetDeleteRelationship() */
10490 : /************************************************************************/
10491 :
10492 : /** Removes a relationship from the dataset.
10493 : *
10494 : * Only a few drivers will support this operation.
10495 : *
10496 : * A dataset having at least some support for this
10497 : * operation should report the GDsCDeleteRelationship dataset capability.
10498 : *
10499 : * Anticipated failures will not be emitted through the CPLError()
10500 : * infrastructure, but will be reported in the ppszFailureReason output
10501 : * parameter.
10502 : *
10503 : * @param hDS Dataset handle.
10504 : * @param pszName The relationship name.
10505 : * @param ppszFailureReason Output parameter. Will contain an error message if
10506 : * an error occurs (*ppszFailureReason to be freed
10507 : * with CPLFree). May be NULL.
10508 : * @return true in case of success.
10509 : * @since GDAL 3.6
10510 : */
10511 6 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10512 : char **ppszFailureReason)
10513 : {
10514 6 : VALIDATE_POINTER1(hDS, __func__, false);
10515 6 : VALIDATE_POINTER1(pszName, __func__, false);
10516 6 : std::string failureReason;
10517 12 : const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10518 6 : pszName, failureReason);
10519 6 : if (ppszFailureReason)
10520 : {
10521 0 : *ppszFailureReason =
10522 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10523 : }
10524 6 : return bRet;
10525 : }
10526 :
10527 : /************************************************************************/
10528 : /* UpdateRelationship() */
10529 : /************************************************************************/
10530 :
10531 : /** Updates an existing relationship by replacing its definition.
10532 : *
10533 : * The existing relationship with matching name will be replaced.
10534 : *
10535 : * Only a few drivers will support this operation, and some of them might only
10536 : * support it only for some types of relationships.
10537 : * A dataset having at least some support for this
10538 : * operation should report the GDsCUpdateRelationship dataset capability.
10539 : *
10540 : * Anticipated failures will not be emitted through the CPLError()
10541 : * infrastructure, but will be reported in the failureReason output parameter.
10542 : *
10543 : * @param relationship The relationship definition.
10544 : * @param failureReason Output parameter. Will contain an error message if
10545 : * an error occurs.
10546 : * @return true in case of success.
10547 : * @since GDAL 3.6
10548 : */
10549 0 : bool GDALDataset::UpdateRelationship(
10550 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10551 : std::string &failureReason)
10552 : {
10553 0 : failureReason = "UpdateRelationship not supported by this driver";
10554 0 : return false;
10555 : }
10556 :
10557 : /************************************************************************/
10558 : /* GDALDatasetUpdateRelationship() */
10559 : /************************************************************************/
10560 :
10561 : /** Updates an existing relationship by replacing its definition.
10562 : *
10563 : * The existing relationship with matching name will be replaced.
10564 : *
10565 : * Only a few drivers will support this operation, and some of them might only
10566 : * support it only for some types of relationships.
10567 : * A dataset having at least some support for this
10568 : * operation should report the GDsCUpdateRelationship dataset capability.
10569 : *
10570 : * Anticipated failures will not be emitted through the CPLError()
10571 : * infrastructure, but will be reported in the failureReason output parameter.
10572 : *
10573 : * @param hDS Dataset handle.
10574 : * @param hRelationship The relationship definition. Contrary to the C++
10575 : * version, the passed object is copied.
10576 : * @param ppszFailureReason Output parameter. Will contain an error message if
10577 : * an error occurs (*ppszFailureReason to be freed
10578 : * with CPLFree). May be NULL.
10579 : * @return true in case of success.
10580 : * @since GDAL 3.5
10581 : */
10582 9 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10583 : GDALRelationshipH hRelationship,
10584 : char **ppszFailureReason)
10585 : {
10586 9 : VALIDATE_POINTER1(hDS, __func__, false);
10587 9 : VALIDATE_POINTER1(hRelationship, __func__, false);
10588 : std::unique_ptr<GDALRelationship> poRelationship(
10589 18 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10590 9 : std::string failureReason;
10591 18 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10592 9 : std::move(poRelationship), failureReason);
10593 9 : if (ppszFailureReason)
10594 : {
10595 0 : *ppszFailureReason =
10596 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10597 : }
10598 9 : return bRet;
10599 : }
10600 :
10601 : /************************************************************************/
10602 : /* GDALDatasetSetQueryLoggerFunc() */
10603 : /************************************************************************/
10604 :
10605 : /**
10606 : * Sets the SQL query logger callback.
10607 : *
10608 : * When supported by the driver, the callback will be called with
10609 : * the executed SQL text, the error message, the execution time in milliseconds,
10610 : * the number of records fetched/affected and the client status data.
10611 : *
10612 : * A value of -1 in the execution time or in the number of records indicates
10613 : * that the values are unknown.
10614 : *
10615 : * @param hDS Dataset handle.
10616 : * @param pfnQueryLoggerFunc Callback function
10617 : * @param poQueryLoggerArg Opaque client status data
10618 : * @return true in case of success.
10619 : * @since GDAL 3.7
10620 : */
10621 1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10622 : GDALQueryLoggerFunc pfnQueryLoggerFunc,
10623 : void *poQueryLoggerArg)
10624 : {
10625 1 : VALIDATE_POINTER1(hDS, __func__, false);
10626 2 : return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10627 1 : poQueryLoggerArg);
10628 : }
10629 :
10630 : //! @cond Doxygen_Suppress
10631 :
10632 : /************************************************************************/
10633 : /* SetEnableOverviews() */
10634 : /************************************************************************/
10635 :
10636 7531 : void GDALDataset::SetEnableOverviews(bool bEnable)
10637 : {
10638 7531 : if (m_poPrivate)
10639 : {
10640 7531 : m_poPrivate->m_bOverviewsEnabled = bEnable;
10641 : }
10642 7531 : }
10643 :
10644 : /************************************************************************/
10645 : /* AreOverviewsEnabled() */
10646 : /************************************************************************/
10647 :
10648 2006520 : bool GDALDataset::AreOverviewsEnabled() const
10649 : {
10650 2006520 : return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10651 : }
10652 :
10653 : /************************************************************************/
10654 : /* IsAllBands() */
10655 : /************************************************************************/
10656 :
10657 3695 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10658 : {
10659 3695 : if (nBands != nBandCount)
10660 1 : return false;
10661 3694 : if (panBandList)
10662 : {
10663 13677 : for (int i = 0; i < nBandCount; ++i)
10664 : {
10665 10077 : if (panBandList[i] != i + 1)
10666 27 : return false;
10667 : }
10668 : }
10669 3667 : return true;
10670 : }
10671 :
10672 : //! @endcond
10673 :
10674 : /************************************************************************/
10675 : /* GetCompressionFormats() */
10676 : /************************************************************************/
10677 :
10678 : /** Return the compression formats that can be natively obtained for the
10679 : * window of interest and requested bands.
10680 : *
10681 : * For example, a tiled dataset may be able to return data in a compressed
10682 : * format if the window of interest matches exactly a tile. For some formats,
10683 : * drivers may also be able to merge several tiles together (not currently
10684 : * implemented though).
10685 : *
10686 : * Each format string is a pseudo MIME type, whose first part can be passed
10687 : * as the pszFormat argument of ReadCompressedData(), with additional
10688 : * parameters specified as key=value with a semi-colon separator.
10689 : *
10690 : * The amount and types of optional parameters passed after the MIME type is
10691 : * format dependent, and driver dependent (some drivers might not be able to
10692 : * return those extra information without doing a rather costly processing).
10693 : *
10694 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10695 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10696 : * consequently "JPEG" can be passed as the pszFormat argument of
10697 : * ReadCompressedData(). For JPEG, implementations can use the
10698 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10699 : * above from a JPEG codestream.
10700 : *
10701 : * Several values might be returned. For example,
10702 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10703 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10704 : *
10705 : * In the general case this method will return an empty list.
10706 : *
10707 : * This is the same as C function GDALDatasetGetCompressionFormats().
10708 : *
10709 : * @param nXOff The pixel offset to the top left corner of the region
10710 : * of the band to be accessed. This would be zero to start from the left side.
10711 : *
10712 : * @param nYOff The line offset to the top left corner of the region
10713 : * of the band to be accessed. This would be zero to start from the top.
10714 : *
10715 : * @param nXSize The width of the region of the band to be accessed in pixels.
10716 : *
10717 : * @param nYSize The height of the region of the band to be accessed in lines.
10718 : *
10719 : * @param nBandCount the number of bands being requested.
10720 : *
10721 : * @param panBandList the list of nBandCount band numbers.
10722 : * Note band numbers are 1 based. This may be NULL to select the first
10723 : * nBandCount bands.
10724 : *
10725 : * @return a list of compatible formats (which may be empty)
10726 : *
10727 : * For example, to check if native compression format(s) are available on the
10728 : * whole image:
10729 : * \code{.cpp}
10730 : * const CPLStringList aosFormats =
10731 : * poDataset->GetCompressionFormats(0, 0,
10732 : * poDataset->GetRasterXSize(),
10733 : * poDataset->GetRasterYSize(),
10734 : * poDataset->GetRasterCount(),
10735 : * nullptr);
10736 : * for( const char* pszFormat: aosFormats )
10737 : * {
10738 : * // Remove optional parameters and just print out the MIME type.
10739 : * const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10740 : * printf("Found format %s\n, aosTokens[0]);
10741 : * }
10742 : * \endcode
10743 : *
10744 : * @since GDAL 3.7
10745 : */
10746 : CPLStringList
10747 0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10748 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10749 : CPL_UNUSED int nBandCount,
10750 : CPL_UNUSED const int *panBandList)
10751 : {
10752 0 : return CPLStringList();
10753 : }
10754 :
10755 : /************************************************************************/
10756 : /* GDALDatasetGetCompressionFormats() */
10757 : /************************************************************************/
10758 :
10759 : /** Return the compression formats that can be natively obtained for the
10760 : * window of interest and requested bands.
10761 : *
10762 : * For example, a tiled dataset may be able to return data in a compressed
10763 : * format if the window of interest matches exactly a tile. For some formats,
10764 : * drivers may also be able to merge several tiles together (not currently
10765 : * implemented though).
10766 : *
10767 : * Each format string is a pseudo MIME type, whose first part can be passed
10768 : * as the pszFormat argument of ReadCompressedData(), with additional
10769 : * parameters specified as key=value with a semi-colon separator.
10770 : *
10771 : * The amount and types of optional parameters passed after the MIME type is
10772 : * format dependent, and driver dependent (some drivers might not be able to
10773 : * return those extra information without doing a rather costly processing).
10774 : *
10775 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10776 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10777 : * consequently "JPEG" can be passed as the pszFormat argument of
10778 : * ReadCompressedData(). For JPEG, implementations can use the
10779 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10780 : * above from a JPEG codestream.
10781 : *
10782 : * Several values might be returned. For example,
10783 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10784 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10785 : *
10786 : * In the general case this method will return an empty list.
10787 : *
10788 : * This is the same as C++ method GDALDataset::GetCompressionFormats().
10789 : *
10790 : * @param hDS Dataset handle.
10791 : *
10792 : * @param nXOff The pixel offset to the top left corner of the region
10793 : * of the band to be accessed. This would be zero to start from the left side.
10794 : *
10795 : * @param nYOff The line offset to the top left corner of the region
10796 : * of the band to be accessed. This would be zero to start from the top.
10797 : *
10798 : * @param nXSize The width of the region of the band to be accessed in pixels.
10799 : *
10800 : * @param nYSize The height of the region of the band to be accessed in lines.
10801 : *
10802 : * @param nBandCount the number of bands being requested.
10803 : *
10804 : * @param panBandList the list of nBandCount band numbers.
10805 : * Note band numbers are 1 based. This may be NULL to select the first
10806 : * nBandCount bands.
10807 : *
10808 : * @return a list of compatible formats (which may be empty) that should be
10809 : * freed with CSLDestroy(), or nullptr.
10810 : *
10811 : * @since GDAL 3.7
10812 : */
10813 9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
10814 : int nXSize, int nYSize, int nBandCount,
10815 : const int *panBandList)
10816 : {
10817 9 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10818 9 : return GDALDataset::FromHandle(hDS)
10819 9 : ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
10820 9 : panBandList)
10821 9 : .StealList();
10822 : }
10823 :
10824 : /************************************************************************/
10825 : /* ReadCompressedData() */
10826 : /************************************************************************/
10827 :
10828 : /** Return the compressed content that can be natively obtained for the
10829 : * window of interest and requested bands.
10830 : *
10831 : * For example, a tiled dataset may be able to return data in compressed format
10832 : * if the window of interest matches exactly a tile. For some formats, drivers
10833 : * may also be example to merge several tiles together (not currently
10834 : * implemented though).
10835 : *
10836 : * The implementation should make sure that the content returned forms a valid
10837 : * standalone file. For example, for the GeoTIFF implementation of this method,
10838 : * when extracting a JPEG tile, the method will automatically add the content
10839 : * of the JPEG Huffman and/or quantization tables that might be stored in the
10840 : * TIFF JpegTables tag, and not in tile data itself.
10841 : *
10842 : * In the general case this method will return CE_Failure.
10843 : *
10844 : * This is the same as C function GDALDatasetReadCompressedData().
10845 : *
10846 : * @param pszFormat Requested compression format (e.g. "JPEG",
10847 : * "WEBP", "JXL"). This is the MIME type of one of the values
10848 : * returned by GetCompressionFormats(). The format string is designed to
10849 : * potentially include at a later point key=value optional parameters separated
10850 : * by a semi-colon character. At time of writing, none are implemented.
10851 : * ReadCompressedData() implementations should verify optional parameters and
10852 : * return CE_Failure if they cannot support one of them.
10853 : *
10854 : * @param nXOff The pixel offset to the top left corner of the region
10855 : * of the band to be accessed. This would be zero to start from the left side.
10856 : *
10857 : * @param nYOff The line offset to the top left corner of the region
10858 : * of the band to be accessed. This would be zero to start from the top.
10859 : *
10860 : * @param nXSize The width of the region of the band to be accessed in pixels.
10861 : *
10862 : * @param nYSize The height of the region of the band to be accessed in lines.
10863 : *
10864 : * @param nBandCount the number of bands being requested.
10865 : *
10866 : * @param panBandList the list of nBandCount band numbers.
10867 : * Note band numbers are 1 based. This may be NULL to select the first
10868 : * nBandCount bands.
10869 : *
10870 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
10871 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
10872 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
10873 : * buffer will be filled with the compressed data, provided that pnBufferSize
10874 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
10875 : * of *ppBuffer, is sufficiently large to hold the data.
10876 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
10877 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
10878 : * free it with VSIFree().
10879 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
10880 : * but *pnBufferSize will be updated with an upper bound of the size that would
10881 : * be necessary to hold it (if pnBufferSize != nullptr).
10882 : *
10883 : * @param pnBufferSize Output buffer size, or nullptr.
10884 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
10885 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
10886 : * method is successful, *pnBufferSize will be updated with the actual size
10887 : * used.
10888 : *
10889 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
10890 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
10891 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
10892 : * *ppszDetailedFormat might contain strings like
10893 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
10894 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
10895 : * The string will contain at least as much information as what
10896 : * GetCompressionFormats() returns, and potentially more when
10897 : * ppBuffer != nullptr.
10898 : *
10899 : * @return CE_None in case of success, CE_Failure otherwise.
10900 : *
10901 : * For example, to request JPEG content on the whole image and let GDAL deal
10902 : * with the buffer allocation.
10903 : * \code{.cpp}
10904 : * void* pBuffer = nullptr;
10905 : * size_t nBufferSize = 0;
10906 : * CPLErr eErr =
10907 : * poDataset->ReadCompressedData("JPEG",
10908 : * 0, 0,
10909 : * poDataset->GetRasterXSize(),
10910 : * poDataset->GetRasterYSize(),
10911 : * poDataset->GetRasterCount(),
10912 : * nullptr, // panBandList
10913 : * &pBuffer,
10914 : * &nBufferSize,
10915 : * nullptr // ppszDetailedFormat
10916 : * );
10917 : * if (eErr == CE_None)
10918 : * {
10919 : * CPLAssert(pBuffer != nullptr);
10920 : * CPLAssert(nBufferSize > 0);
10921 : * VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
10922 : * if (fp)
10923 : * {
10924 : * VSIFWriteL(pBuffer, nBufferSize, 1, fp);
10925 : * VSIFCloseL(fp);
10926 : * }
10927 : * VSIFree(pBuffer);
10928 : * }
10929 : * \endcode
10930 : *
10931 : * Or to manage the buffer allocation on your side:
10932 : * \code{.cpp}
10933 : * size_t nUpperBoundBufferSize = 0;
10934 : * CPLErr eErr =
10935 : * poDataset->ReadCompressedData("JPEG",
10936 : * 0, 0,
10937 : * poDataset->GetRasterXSize(),
10938 : * poDataset->GetRasterYSize(),
10939 : * poDataset->GetRasterCount(),
10940 : * nullptr, // panBandList
10941 : * nullptr, // ppBuffer,
10942 : * &nUpperBoundBufferSize,
10943 : * nullptr // ppszDetailedFormat
10944 : * );
10945 : * if (eErr == CE_None)
10946 : * {
10947 : * std::vector<uint8_t> myBuffer;
10948 : * myBuffer.resize(nUpperBoundBufferSize);
10949 : * void* pBuffer = myBuffer.data();
10950 : * size_t nActualSize = nUpperBoundBufferSize;
10951 : * char* pszDetailedFormat = nullptr;
10952 : * // We also request detailed format, but we could have passed it to
10953 : * // nullptr as well.
10954 : * eErr =
10955 : * poDataset->ReadCompressedData("JPEG",
10956 : * 0, 0,
10957 : * poDataset->GetRasterXSize(),
10958 : * poDataset->GetRasterYSize(),
10959 : * poDataset->GetRasterCount(),
10960 : * nullptr, // panBandList
10961 : * &pBuffer,
10962 : * &nActualSize,
10963 : * &pszDetailedFormat);
10964 : * if (eErr == CE_None)
10965 : * {
10966 : * CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
10967 : * CPLAssert(nActualSize <= nUpperBoundBufferSize);
10968 : * myBuffer.resize(nActualSize);
10969 : * // do something useful
10970 : * VSIFree(pszDetailedFormat);
10971 : * }
10972 : * }
10973 : * \endcode
10974 : *
10975 : * @since GDAL 3.7
10976 : */
10977 441 : CPLErr GDALDataset::ReadCompressedData(
10978 : CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
10979 : CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10980 : CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
10981 : CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
10982 : CPL_UNUSED char **ppszDetailedFormat)
10983 : {
10984 441 : return CE_Failure;
10985 : }
10986 :
10987 : /************************************************************************/
10988 : /* GDALDatasetReadCompressedData() */
10989 : /************************************************************************/
10990 :
10991 : /** Return the compressed content that can be natively obtained for the
10992 : * window of interest and requested bands.
10993 : *
10994 : * For example, a tiled dataset may be able to return data in compressed format
10995 : * if the window of interest matches exactly a tile. For some formats, drivers
10996 : * may also be example to merge several tiles together (not currently
10997 : * implemented though).
10998 : *
10999 : * The implementation should make sure that the content returned forms a valid
11000 : * standalone file. For example, for the GeoTIFF implementation of this method,
11001 : * when extracting a JPEG tile, the method will automatically adds the content
11002 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11003 : * TIFF JpegTables tag, and not in tile data itself.
11004 : *
11005 : * In the general case this method will return CE_Failure.
11006 : *
11007 : * This is the same as C++ method GDALDataset:ReadCompressedData().
11008 : *
11009 : * @param hDS Dataset handle.
11010 : *
11011 : * @param pszFormat Requested compression format (e.g. "JPEG",
11012 : * "WEBP", "JXL"). This is the MIME type of one of the values
11013 : * returned by GetCompressionFormats(). The format string is designed to
11014 : * potentially include at a later point key=value optional parameters separated
11015 : * by a semi-colon character. At time of writing, none are implemented.
11016 : * ReadCompressedData() implementations should verify optional parameters and
11017 : * return CE_Failure if they cannot support one of them.
11018 : *
11019 : * @param nXOff The pixel offset to the top left corner of the region
11020 : * of the band to be accessed. This would be zero to start from the left side.
11021 : *
11022 : * @param nYOff The line offset to the top left corner of the region
11023 : * of the band to be accessed. This would be zero to start from the top.
11024 : *
11025 : * @param nXSize The width of the region of the band to be accessed in pixels.
11026 : *
11027 : * @param nYSize The height of the region of the band to be accessed in lines.
11028 : *
11029 : * @param nBandCount the number of bands being requested.
11030 : *
11031 : * @param panBandList the list of nBandCount band numbers.
11032 : * Note band numbers are 1 based. This may be NULL to select the first
11033 : * nBandCount bands.
11034 : *
11035 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11036 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11037 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11038 : * buffer will be filled with the compressed data, provided that pnBufferSize
11039 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11040 : * of *ppBuffer, is sufficiently large to hold the data.
11041 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11042 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11043 : * free it with VSIFree().
11044 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11045 : * but *pnBufferSize will be updated with an upper bound of the size that would
11046 : * be necessary to hold it (if pnBufferSize != nullptr).
11047 : *
11048 : * @param pnBufferSize Output buffer size, or nullptr.
11049 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11050 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11051 : * method is successful, *pnBufferSize will be updated with the actual size
11052 : * used.
11053 : *
11054 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11055 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11056 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11057 : * *ppszDetailedFormat might contain strings like
11058 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11059 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11060 : * The string will contain at least as much information as what
11061 : * GetCompressionFormats() returns, and potentially more when
11062 : * ppBuffer != nullptr.
11063 : *
11064 : * @return CE_None in case of success, CE_Failure otherwise.
11065 : *
11066 : * @since GDAL 3.7
11067 : */
11068 28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11069 : int nXOff, int nYOff, int nXSize,
11070 : int nYSize, int nBandCount,
11071 : const int *panBandList, void **ppBuffer,
11072 : size_t *pnBufferSize,
11073 : char **ppszDetailedFormat)
11074 : {
11075 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11076 56 : return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11077 : pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11078 28 : ppBuffer, pnBufferSize, ppszDetailedFormat);
11079 : }
11080 :
11081 : /************************************************************************/
11082 : /* CanBeCloned() */
11083 : /************************************************************************/
11084 :
11085 : //! @cond Doxygen_Suppress
11086 :
11087 : /** This method is called by GDALThreadSafeDataset::Create() to determine if
11088 : * it is possible to create a thread-safe wrapper for a dataset, which involves
11089 : * the ability to Clone() it.
11090 : *
11091 : * Implementations of this method must be thread-safe.
11092 : *
11093 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11094 : * expressing the intended use for thread-safety.
11095 : * Currently, the only valid scope is in the base
11096 : * implementation is GDAL_OF_RASTER.
11097 : * @param bCanShareState Determines if cloned datasets are allowed to share
11098 : * state with the dataset they have been cloned from.
11099 : * If set to true, the dataset from which they have been
11100 : * cloned from must remain opened during the lifetime of
11101 : * its clones.
11102 : * @return true if the Clone() method is expected to succeed with the same values
11103 : * of nScopeFlags and bCanShareState.
11104 : */
11105 149 : bool GDALDataset::CanBeCloned(int nScopeFlags,
11106 : [[maybe_unused]] bool bCanShareState) const
11107 : {
11108 149 : return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11109 : }
11110 :
11111 : //! @endcond
11112 :
11113 : /************************************************************************/
11114 : /* Clone() */
11115 : /************************************************************************/
11116 :
11117 : //! @cond Doxygen_Suppress
11118 :
11119 : /** This method "clones" the current dataset, that is it returns a new instance
11120 : * that is opened on the same underlying "file".
11121 : *
11122 : * The base implementation uses GDALDataset::Open() to re-open the dataset.
11123 : * The MEM driver has a specialized implementation that returns a new instance,
11124 : * but which shares the same memory buffer as this.
11125 : *
11126 : * Implementations of this method must be thread-safe.
11127 : *
11128 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11129 : * expressing the intended use for thread-safety.
11130 : * Currently, the only valid scope is in the base
11131 : * implementation is GDAL_OF_RASTER.
11132 : * @param bCanShareState Determines if cloned datasets are allowed to share
11133 : * state with the dataset they have been cloned from.
11134 : * If set to true, the dataset from which they have been
11135 : * cloned from must remain opened during the lifetime of
11136 : * its clones.
11137 : * @return a new instance, or nullptr in case of error.
11138 : */
11139 : std::unique_ptr<GDALDataset>
11140 2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11141 : {
11142 4102 : CPLStringList aosAllowedDrivers;
11143 2051 : if (poDriver)
11144 2051 : aosAllowedDrivers.AddString(poDriver->GetDescription());
11145 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11146 2051 : GetDescription(),
11147 2051 : nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11148 4102 : aosAllowedDrivers.List(), papszOpenOptions));
11149 : }
11150 :
11151 : //! @endcond
11152 :
11153 : /************************************************************************/
11154 : /* GeolocationToPixelLine() */
11155 : /************************************************************************/
11156 :
11157 : /** Transform georeferenced coordinates to pixel/line coordinates.
11158 : *
11159 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11160 : * must be in the "natural" SRS of the dataset, that is the one returned by
11161 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11162 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11163 : * array (generally WGS 84) if there is a geolocation array.
11164 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11165 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11166 : * be a easting, and dfGeolocY a northing.
11167 : *
11168 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11169 : * expressed in that CRS, and that tuple must be conformant with the
11170 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11171 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11172 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11173 : * before calling this method, and in that case, dfGeolocX must be a longitude
11174 : * or an easting value, and dfGeolocX a latitude or a northing value.
11175 : *
11176 : * This method uses GDALCreateGenImgProjTransformer2() underneath.
11177 : *
11178 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11179 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11180 : * where interpolation should be done.
11181 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11182 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11183 : * where interpolation should be done.
11184 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11185 : * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11186 : * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11187 : * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11188 : *
11189 : * @return CE_None on success, or an error code on failure.
11190 : * @since GDAL 3.11
11191 : */
11192 :
11193 : CPLErr
11194 15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11195 : const OGRSpatialReference *poSRS,
11196 : double *pdfPixel, double *pdfLine,
11197 : CSLConstList papszTransformerOptions) const
11198 : {
11199 30 : CPLStringList aosTO(papszTransformerOptions);
11200 :
11201 15 : if (poSRS)
11202 : {
11203 4 : const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11204 8 : const std::string osWKT = poSRS->exportToWkt(apszOptions);
11205 4 : aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11206 4 : const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11207 4 : if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11208 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11209 1 : "TRADITIONAL_GIS_ORDER");
11210 3 : else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11211 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11212 1 : "AUTHORITY_COMPLIANT");
11213 : else
11214 : {
11215 2 : const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11216 4 : std::string osVal;
11217 6 : for (int v : anValues)
11218 : {
11219 4 : if (!osVal.empty())
11220 2 : osVal += ',';
11221 4 : osVal += std::to_string(v);
11222 : }
11223 : aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11224 2 : osVal.c_str());
11225 : }
11226 : }
11227 :
11228 15 : auto hTransformer = GDALCreateGenImgProjTransformer2(
11229 : GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11230 15 : aosTO.List());
11231 15 : if (hTransformer == nullptr)
11232 : {
11233 1 : return CE_Failure;
11234 : }
11235 :
11236 14 : double z = 0;
11237 14 : int bSuccess = 0;
11238 14 : GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11239 : &bSuccess);
11240 14 : GDALDestroyTransformer(hTransformer);
11241 14 : if (bSuccess)
11242 : {
11243 14 : if (pdfPixel)
11244 14 : *pdfPixel = dfGeolocX;
11245 14 : if (pdfLine)
11246 14 : *pdfLine = dfGeolocY;
11247 14 : return CE_None;
11248 : }
11249 : else
11250 : {
11251 0 : return CE_Failure;
11252 : }
11253 : }
11254 :
11255 : /************************************************************************/
11256 : /* GDALDatasetGeolocationToPixelLine() */
11257 : /************************************************************************/
11258 :
11259 : /** Transform georeferenced coordinates to pixel/line coordinates.
11260 : *
11261 : * @see GDALDataset::GeolocationToPixelLine()
11262 : * @since GDAL 3.11
11263 : */
11264 :
11265 0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11266 : double dfGeolocY,
11267 : OGRSpatialReferenceH hSRS,
11268 : double *pdfPixel, double *pdfLine,
11269 : CSLConstList papszTransformerOptions)
11270 : {
11271 0 : VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11272 :
11273 0 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11274 0 : return poDS->GeolocationToPixelLine(
11275 0 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11276 0 : pdfLine, papszTransformerOptions);
11277 : }
11278 :
11279 : /************************************************************************/
11280 : /* GetExtent() */
11281 : /************************************************************************/
11282 :
11283 : /** Return extent of dataset in specified CRS.
11284 : *
11285 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11286 : *
11287 : * For rasters, the base implementation of this method only succeeds if
11288 : * GetGeoTransform() and GetSpatialRef() succeed.
11289 : * For vectors, the base implementation of this method iterates over layers
11290 : * and call their OGRLayer::GetExtent() method.
11291 : *
11292 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11293 : * time of this method is fast.
11294 : *
11295 : * This is the same as C function GDALGetExtent()
11296 : *
11297 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11298 : * @param poCRS CRS in which to express the extent. If not specified, this will
11299 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11300 : * @return CE_None in case of success, CE_Failure otherwise
11301 : * @since GDAL 3.12
11302 : */
11303 :
11304 229 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11305 : const OGRSpatialReference *poCRS) const
11306 : {
11307 229 : const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11308 229 : int nLayerCount = 0;
11309 229 : if (!poThisCRS)
11310 : {
11311 93 : nLayerCount = GetLayerCount();
11312 93 : if (nLayerCount >= 1)
11313 : {
11314 3 : if (auto poLayer = GetLayer(0))
11315 3 : poThisCRS = poLayer->GetSpatialRef();
11316 : }
11317 : }
11318 229 : if (!poCRS)
11319 131 : poCRS = poThisCRS;
11320 98 : else if (!poThisCRS)
11321 3 : return CE_Failure;
11322 :
11323 226 : *psExtent = OGREnvelope();
11324 :
11325 226 : GDALGeoTransform gt;
11326 226 : auto poThisDS = const_cast<GDALDataset *>(this);
11327 226 : const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11328 226 : if (bHasGT)
11329 : {
11330 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
11331 221 : if (poCRS)
11332 : {
11333 136 : poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11334 : }
11335 :
11336 221 : constexpr int DENSIFY_POINT_COUNT = 21;
11337 221 : double dfULX = gt[0];
11338 221 : double dfULY = gt[3];
11339 221 : double dfURX = 0, dfURY = 0;
11340 221 : gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11341 221 : double dfLLX = 0, dfLLY = 0;
11342 221 : gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11343 221 : double dfLRX = 0, dfLRY = 0;
11344 221 : gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11345 221 : const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11346 221 : const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11347 221 : const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11348 221 : const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11349 221 : if (poCT)
11350 : {
11351 136 : OGREnvelope sEnvTmp;
11352 272 : if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11353 : &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11354 136 : &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11355 : {
11356 0 : return CE_Failure;
11357 : }
11358 136 : *psExtent = sEnvTmp;
11359 : }
11360 : else
11361 : {
11362 85 : psExtent->MinX = xmin;
11363 85 : psExtent->MinY = ymin;
11364 85 : psExtent->MaxX = xmax;
11365 85 : psExtent->MaxY = ymax;
11366 : }
11367 : }
11368 :
11369 226 : if (nLayerCount > 0)
11370 : {
11371 6 : for (auto &&poLayer : poThisDS->GetLayers())
11372 : {
11373 3 : auto poLayerCRS = poLayer->GetSpatialRef();
11374 3 : if (poLayerCRS)
11375 : {
11376 3 : OGREnvelope sLayerExtent;
11377 3 : if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11378 : {
11379 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11380 6 : OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11381 3 : if (poCT)
11382 : {
11383 3 : constexpr int DENSIFY_POINT_COUNT = 21;
11384 3 : OGREnvelope sEnvTmp;
11385 3 : if (poCT->TransformBounds(
11386 : sLayerExtent.MinX, sLayerExtent.MinY,
11387 : sLayerExtent.MaxX, sLayerExtent.MaxY,
11388 : &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11389 : &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11390 3 : DENSIFY_POINT_COUNT))
11391 : {
11392 3 : psExtent->Merge(sEnvTmp);
11393 : }
11394 : }
11395 : }
11396 : }
11397 : }
11398 : }
11399 :
11400 226 : return psExtent->IsInit() ? CE_None : CE_Failure;
11401 : }
11402 :
11403 : /************************************************************************/
11404 : /* GDALGetExtent() */
11405 : /************************************************************************/
11406 :
11407 : /** Return extent of dataset in specified CRS.
11408 : *
11409 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11410 : *
11411 : * For rasters, the base implementation of this method only succeeds if
11412 : * GetGeoTransform() and GetSpatialRef() succeed.
11413 : * For vectors, the base implementation of this method iterates over layers
11414 : * and call their OGRLayer::GetExtent() method.
11415 : *
11416 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11417 : * time of this method is fast.
11418 : *
11419 : * This is the same as C++ method GDALDataset::GetExtent()
11420 : *
11421 : * @param hDS Dataset handle. Must NOT be null.
11422 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11423 : * @param hCRS CRS in which to express the extent. If not specified, this will
11424 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11425 : * @return extent in poCRS (valid only if IsInit() method returns true)
11426 : * @since GDAL 3.12
11427 : */
11428 :
11429 28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11430 : OGRSpatialReferenceH hCRS)
11431 : {
11432 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11433 28 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11434 56 : return GDALDataset::FromHandle(hDS)->GetExtent(
11435 28 : psExtent, OGRSpatialReference::FromHandle(hCRS));
11436 : }
11437 :
11438 : /************************************************************************/
11439 : /* GetExtentWGS84LongLat() */
11440 : /************************************************************************/
11441 :
11442 : /** Return extent of dataset in WGS84 longitude/latitude
11443 : *
11444 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11445 : *
11446 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11447 : * time of this method is fast.
11448 : *
11449 : * This is the same as C function GDALGetExtentWGS84LongLat()
11450 : *
11451 : * @return extent (valid only if IsInit() method returns true)
11452 : * @since GDAL 3.12
11453 : */
11454 :
11455 96 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11456 : {
11457 192 : OGRSpatialReference oSRS_WGS84;
11458 96 : oSRS_WGS84.SetFromUserInput("WGS84");
11459 96 : oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11460 192 : return GetExtent(psExtent, &oSRS_WGS84);
11461 : }
11462 :
11463 : /************************************************************************/
11464 : /* GDALGetExtentWGS84LongLat() */
11465 : /************************************************************************/
11466 :
11467 : /** Return extent of dataset in WGS84 longitude/latitude
11468 : *
11469 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11470 : *
11471 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11472 : * time of this method is fast.
11473 : *
11474 : * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11475 : *
11476 : * @param hDS Dataset handle. Must NOT be null.
11477 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11478 : * @return extent (valid only if IsInit() method returns true)
11479 : * @since GDAL 3.12
11480 : */
11481 :
11482 4 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11483 : {
11484 4 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11485 4 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11486 4 : return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11487 : }
11488 :
11489 : /************************************************************************/
11490 : /* ReportUpdateNotSupportedByDriver() */
11491 : /************************************************************************/
11492 :
11493 : //! @cond Doxygen_Suppress
11494 :
11495 : /* static */
11496 1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11497 : {
11498 1 : CPLError(CE_Failure, CPLE_NotSupported,
11499 : "The %s driver does not support update access to existing "
11500 : "datasets.",
11501 : pszDriverName);
11502 1 : }
11503 :
11504 : //! @endcond
11505 :
11506 : /************************************************************************/
11507 : /* BuildFilename() */
11508 : /************************************************************************/
11509 :
11510 : /** Generates a filename, potentially relative to another one.
11511 : *
11512 : * Given the path to a reference directory, and a path to a file
11513 : * referenced from it, build a path to the file that the current application
11514 : * can use. If the file path is already absolute, rather than relative, or if
11515 : * bRelativeToReferencePath is false, then the filename of interest will be
11516 : * returned unaltered.
11517 : *
11518 : * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11519 : * into account the subdataset syntax.
11520 : *
11521 : * Examples:
11522 : * \code{.cpp}
11523 : * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11524 : * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11525 : * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11526 : * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11527 : * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11528 : * \endcode
11529 : *
11530 : * @param pszFilename Filename of interest.
11531 : * @param pszReferencePath Path to a reference directory.
11532 : * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11533 : * relative to pszReferencePath
11534 : * @since 3.11
11535 : */
11536 :
11537 : /* static */
11538 104264 : std::string GDALDataset::BuildFilename(const char *pszFilename,
11539 : const char *pszReferencePath,
11540 : bool bRelativeToReferencePath)
11541 : {
11542 104264 : std::string osSrcDSName;
11543 104264 : if (pszReferencePath != nullptr && bRelativeToReferencePath)
11544 : {
11545 : // Try subdatasetinfo API first
11546 : // Note: this will become the only branch when subdatasetinfo will become
11547 : // available for NITF_IM, RASTERLITE and TILEDB
11548 2594 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11549 2594 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11550 : {
11551 8 : auto path{oSubDSInfo->GetPathComponent()};
11552 12 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
11553 8 : CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11554 4 : .c_str());
11555 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
11556 : }
11557 : else
11558 : {
11559 2590 : bool bDone = false;
11560 15525 : for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11561 : {
11562 12938 : CPLString osPrefix(pszSyntax);
11563 12938 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11564 12938 : if (pszSyntax[osPrefix.size()] == '"')
11565 2587 : osPrefix += '"';
11566 12938 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11567 : {
11568 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11569 : {
11570 3 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11571 : // CSV:z:/foo.xyz
11572 3 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11573 0 : pszLastPart - pszFilename >= 3 &&
11574 0 : pszLastPart[-3] == ':')
11575 : {
11576 0 : pszLastPart -= 2;
11577 : }
11578 3 : CPLString osPrefixFilename = pszFilename;
11579 3 : osPrefixFilename.resize(pszLastPart - pszFilename);
11580 6 : osSrcDSName = osPrefixFilename +
11581 6 : CPLProjectRelativeFilenameSafe(
11582 3 : pszReferencePath, pszLastPart);
11583 3 : bDone = true;
11584 : }
11585 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11586 : "{FILENAME}"))
11587 : {
11588 0 : CPLString osFilename(pszFilename + osPrefix.size());
11589 0 : size_t nPos = 0;
11590 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11591 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
11592 0 : nPos = 2;
11593 0 : nPos = osFilename.find(
11594 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11595 : nPos);
11596 0 : if (nPos != std::string::npos)
11597 : {
11598 0 : const CPLString osSuffix = osFilename.substr(nPos);
11599 0 : osFilename.resize(nPos);
11600 0 : osSrcDSName = osPrefix +
11601 0 : CPLProjectRelativeFilenameSafe(
11602 0 : pszReferencePath, osFilename) +
11603 0 : osSuffix;
11604 0 : bDone = true;
11605 : }
11606 : }
11607 3 : break;
11608 : }
11609 : }
11610 2590 : if (!bDone)
11611 : {
11612 2587 : std::string osReferencePath = pszReferencePath;
11613 2587 : if (!CPLIsFilenameRelative(pszReferencePath))
11614 : {
11615 : // Simplify path by replacing "foo/a/../b" with "foo/b"
11616 2294 : while (STARTS_WITH(pszFilename, "../"))
11617 : {
11618 : osReferencePath =
11619 5 : CPLGetPathSafe(osReferencePath.c_str());
11620 5 : pszFilename += strlen("../");
11621 : }
11622 : }
11623 :
11624 5174 : osSrcDSName = CPLProjectRelativeFilenameSafe(
11625 2587 : osReferencePath.c_str(), pszFilename);
11626 : }
11627 2594 : }
11628 : }
11629 : else
11630 : {
11631 101670 : osSrcDSName = pszFilename;
11632 : }
11633 104264 : return osSrcDSName;
11634 : }
11635 :
11636 : /************************************************************************/
11637 : /* GDALMDArrayFromDataset */
11638 : /************************************************************************/
11639 :
11640 : class GDALMDArrayFromDataset final : public GDALMDArray
11641 : {
11642 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11643 :
11644 : GDALDataset *const m_poDS;
11645 : const GDALExtendedDataType m_dt;
11646 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11647 : std::string m_osUnit{};
11648 : std::vector<GByte> m_abyNoData{};
11649 : std::shared_ptr<GDALMDArray> m_varX{};
11650 : std::shared_ptr<GDALMDArray> m_varY{};
11651 : std::shared_ptr<GDALMDArray> m_varBand{};
11652 : const std::string m_osFilename;
11653 : int m_iBandDim = 0;
11654 : int m_iYDim = 1;
11655 : int m_iXDim = 2;
11656 :
11657 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11658 : const size_t *count, const GInt64 *arrayStep,
11659 : const GPtrDiff_t *bufferStride,
11660 : const GDALExtendedDataType &bufferDataType,
11661 : void *pBuffer) const;
11662 :
11663 : protected:
11664 15 : GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11665 30 : : GDALAbstractMDArray(std::string(),
11666 30 : std::string(poDS->GetDescription())),
11667 30 : GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11668 : m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11669 : poDS->GetRasterBand(1)->GetRasterDataType())),
11670 75 : m_osFilename(poDS->GetDescription())
11671 : {
11672 15 : m_poDS->Reference();
11673 :
11674 15 : const int nBandCount = poDS->GetRasterCount();
11675 43 : for (int i = 1; i <= nBandCount; ++i)
11676 : {
11677 28 : const auto poBand = poDS->GetRasterBand(i);
11678 28 : if (i == 1)
11679 15 : m_osUnit = poBand->GetUnitType();
11680 13 : else if (m_osUnit != poBand->GetUnitType())
11681 7 : m_osUnit.clear();
11682 :
11683 56 : std::vector<GByte> abyNoData;
11684 28 : int bHasNoData = false;
11685 28 : switch (poBand->GetRasterDataType())
11686 : {
11687 0 : case GDT_Int64:
11688 : {
11689 : const auto nNoData =
11690 0 : poBand->GetNoDataValueAsInt64(&bHasNoData);
11691 0 : if (bHasNoData)
11692 : {
11693 0 : abyNoData.resize(m_dt.GetSize());
11694 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11695 : m_dt.GetNumericDataType(), 0, 1);
11696 : }
11697 0 : break;
11698 : }
11699 :
11700 0 : case GDT_UInt64:
11701 : {
11702 : const auto nNoData =
11703 0 : poBand->GetNoDataValueAsUInt64(&bHasNoData);
11704 0 : if (bHasNoData)
11705 : {
11706 0 : abyNoData.resize(m_dt.GetSize());
11707 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11708 : m_dt.GetNumericDataType(), 0, 1);
11709 : }
11710 0 : break;
11711 : }
11712 :
11713 28 : default:
11714 : {
11715 28 : const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11716 28 : if (bHasNoData)
11717 : {
11718 11 : abyNoData.resize(m_dt.GetSize());
11719 22 : GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11720 11 : &abyNoData[0],
11721 : m_dt.GetNumericDataType(), 0, 1);
11722 : }
11723 28 : break;
11724 : }
11725 : }
11726 :
11727 28 : if (i == 1)
11728 15 : m_abyNoData = std::move(abyNoData);
11729 13 : else if (m_abyNoData != abyNoData)
11730 7 : m_abyNoData.clear();
11731 : }
11732 :
11733 15 : const int nXSize = poDS->GetRasterXSize();
11734 15 : const int nYSize = poDS->GetRasterYSize();
11735 :
11736 15 : auto poSRS = poDS->GetSpatialRef();
11737 30 : std::string osTypeY;
11738 30 : std::string osTypeX;
11739 30 : std::string osDirectionY;
11740 30 : std::string osDirectionX;
11741 15 : if (poSRS && poSRS->GetAxesCount() == 2)
11742 : {
11743 8 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11744 8 : OGRAxisOrientation eOrientation1 = OAO_Other;
11745 8 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11746 8 : OGRAxisOrientation eOrientation2 = OAO_Other;
11747 8 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11748 8 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11749 : {
11750 6 : if (mapping == std::vector<int>{1, 2})
11751 : {
11752 6 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11753 6 : osDirectionY = "NORTH";
11754 6 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11755 6 : osDirectionX = "EAST";
11756 : }
11757 : }
11758 2 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11759 : {
11760 2 : if (mapping == std::vector<int>{2, 1})
11761 : {
11762 2 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11763 2 : osDirectionY = "NORTH";
11764 2 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11765 2 : osDirectionX = "EAST";
11766 : }
11767 : }
11768 : }
11769 :
11770 41 : const bool bBandYX = [papszOptions, poDS, nBandCount]()
11771 : {
11772 : const char *pszDimOrder =
11773 15 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11774 15 : if (EQUAL(pszDimOrder, "AUTO"))
11775 : {
11776 : const char *pszInterleave =
11777 13 : poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11778 22 : return nBandCount == 1 || !pszInterleave ||
11779 22 : !EQUAL(pszInterleave, "PIXEL");
11780 : }
11781 : else
11782 : {
11783 2 : return EQUAL(pszDimOrder, "BAND,Y,X");
11784 : }
11785 15 : }();
11786 : const char *const pszBandDimName =
11787 15 : CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11788 : auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11789 45 : "/", pszBandDimName, std::string(), std::string(), nBandCount);
11790 : const char *const pszYDimName =
11791 15 : CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11792 : auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11793 30 : "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11794 : const char *const pszXDimName =
11795 15 : CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11796 : auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11797 30 : "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11798 :
11799 15 : const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11800 : papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
11801 15 : if (EQUAL(pszBandIndexingVarItem, "{Description}"))
11802 : {
11803 : const auto oIndexingVarType =
11804 18 : GDALExtendedDataType::CreateString(strlen("Band 65535"));
11805 9 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11806 36 : {poBandDim}, oIndexingVarType);
11807 9 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11808 25 : for (int i = 0; i < nBandCount; ++i)
11809 : {
11810 : const char *pszDesc =
11811 16 : poDS->GetRasterBand(i + 1)->GetDescription();
11812 : const std::string osBandName =
11813 32 : pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
11814 16 : const char *pszBandName = osBandName.c_str();
11815 16 : const char *const apszBandVal[] = {pszBandName};
11816 16 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11817 16 : const size_t anCount[] = {1};
11818 16 : const GInt64 arrayStep[] = {1};
11819 16 : const GPtrDiff_t anBufferStride[] = {1};
11820 16 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11821 : oIndexingVarType, apszBandVal);
11822 : }
11823 9 : m_varBand = std::move(poBandVar);
11824 9 : poBandDim->SetIndexingVariable(m_varBand);
11825 : }
11826 6 : else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
11827 : {
11828 : const auto oIndexingVarType =
11829 2 : GDALExtendedDataType::Create(GDT_Int32);
11830 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11831 4 : {poBandDim}, oIndexingVarType);
11832 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11833 3 : for (int i = 0; i < nBandCount; ++i)
11834 : {
11835 2 : const int anBandIdx[] = {i + 1};
11836 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11837 2 : const size_t anCount[] = {1};
11838 2 : const GInt64 arrayStep[] = {1};
11839 2 : const GPtrDiff_t anBufferStride[] = {1};
11840 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11841 : oIndexingVarType, anBandIdx);
11842 : }
11843 1 : m_varBand = std::move(poBandVar);
11844 1 : poBandDim->SetIndexingVariable(m_varBand);
11845 : }
11846 5 : else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
11847 : {
11848 1 : size_t nMaxLen = 0;
11849 3 : for (int i = 0; i < nBandCount; ++i)
11850 : {
11851 2 : const char *pszDesc = GDALGetColorInterpretationName(
11852 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11853 2 : nMaxLen = std::max(nMaxLen, strlen(pszDesc));
11854 : }
11855 : const auto oIndexingVarType =
11856 2 : GDALExtendedDataType::CreateString(nMaxLen);
11857 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11858 4 : {poBandDim}, oIndexingVarType);
11859 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11860 3 : for (int i = 0; i < nBandCount; ++i)
11861 : {
11862 2 : const char *pszDesc = GDALGetColorInterpretationName(
11863 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11864 2 : const char *const apszBandVal[] = {pszDesc};
11865 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11866 2 : const size_t anCount[] = {1};
11867 2 : const GInt64 arrayStep[] = {1};
11868 2 : const GPtrDiff_t anBufferStride[] = {1};
11869 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11870 : oIndexingVarType, apszBandVal);
11871 : }
11872 1 : m_varBand = std::move(poBandVar);
11873 1 : poBandDim->SetIndexingVariable(m_varBand);
11874 : }
11875 4 : else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
11876 : {
11877 3 : const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
11878 : papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
11879 3 : size_t nMaxLen = 0;
11880 3 : if (EQUAL(pszBandIndexingVarType, "String"))
11881 : {
11882 3 : for (int i = 0; i < nBandCount; ++i)
11883 : {
11884 : const char *pszVal =
11885 2 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
11886 2 : pszBandIndexingVarItem);
11887 2 : if (pszVal)
11888 1 : nMaxLen = std::max(nMaxLen, strlen(pszVal));
11889 : }
11890 : }
11891 : const auto oIndexingVarType =
11892 3 : EQUAL(pszBandIndexingVarType, "String")
11893 : ? GDALExtendedDataType::CreateString(nMaxLen)
11894 2 : : EQUAL(pszBandIndexingVarType, "Integer")
11895 : ? GDALExtendedDataType::Create(GDT_Int32)
11896 6 : : GDALExtendedDataType::Create(GDT_Float64);
11897 3 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11898 12 : {poBandDim}, oIndexingVarType);
11899 3 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11900 9 : for (int i = 0; i < nBandCount; ++i)
11901 : {
11902 6 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11903 6 : const size_t anCount[] = {1};
11904 6 : const GInt64 arrayStep[] = {1};
11905 6 : const GPtrDiff_t anBufferStride[] = {1};
11906 : const char *pszVal =
11907 6 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
11908 6 : pszBandIndexingVarItem);
11909 6 : if (oIndexingVarType.GetClass() == GEDTC_STRING)
11910 : {
11911 2 : const char *const apszBandVal[] = {pszVal ? pszVal : ""};
11912 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
11913 : anBufferStride, oIndexingVarType,
11914 : apszBandVal);
11915 : }
11916 4 : else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
11917 : {
11918 2 : const int anVal[] = {pszVal ? atoi(pszVal) : 0};
11919 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
11920 : anBufferStride, oIndexingVarType, anVal);
11921 : }
11922 : else
11923 : {
11924 2 : const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
11925 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
11926 : anBufferStride, oIndexingVarType, adfVal);
11927 : }
11928 : }
11929 3 : m_varBand = std::move(poBandVar);
11930 3 : poBandDim->SetIndexingVariable(m_varBand);
11931 : }
11932 :
11933 15 : GDALGeoTransform gt;
11934 15 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
11935 : {
11936 24 : m_varX = GDALMDArrayRegularlySpaced::Create(
11937 24 : "/", poBandDim->GetName(), poXDim, gt[0], gt[1], 0.5);
11938 8 : poXDim->SetIndexingVariable(m_varX);
11939 :
11940 24 : m_varY = GDALMDArrayRegularlySpaced::Create(
11941 24 : "/", poYDim->GetName(), poYDim, gt[3], gt[5], 0.5);
11942 8 : poYDim->SetIndexingVariable(m_varY);
11943 : }
11944 15 : if (bBandYX)
11945 : {
11946 84 : m_dims = {std::move(poBandDim), std::move(poYDim),
11947 70 : std::move(poXDim)};
11948 : }
11949 : else
11950 : {
11951 1 : m_iYDim = 0;
11952 1 : m_iXDim = 1;
11953 1 : m_iBandDim = 2;
11954 6 : m_dims = {std::move(poYDim), std::move(poXDim),
11955 5 : std::move(poBandDim)};
11956 : }
11957 15 : }
11958 :
11959 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11960 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11961 : const GDALExtendedDataType &bufferDataType,
11962 : void *pDstBuffer) const override;
11963 :
11964 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11965 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11966 : const GDALExtendedDataType &bufferDataType,
11967 : const void *pSrcBuffer) override
11968 : {
11969 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11970 : bufferStride, bufferDataType,
11971 1 : const_cast<void *>(pSrcBuffer));
11972 : }
11973 :
11974 : public:
11975 30 : ~GDALMDArrayFromDataset() override
11976 15 : {
11977 15 : m_poDS->ReleaseRef();
11978 30 : }
11979 :
11980 15 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11981 : CSLConstList papszOptions)
11982 : {
11983 : auto array(std::shared_ptr<GDALMDArrayFromDataset>(
11984 30 : new GDALMDArrayFromDataset(poDS, papszOptions)));
11985 15 : array->SetSelf(array);
11986 30 : return array;
11987 : }
11988 :
11989 2 : bool IsWritable() const override
11990 : {
11991 2 : return m_poDS->GetAccess() == GA_Update;
11992 : }
11993 :
11994 16 : const std::string &GetFilename() const override
11995 : {
11996 16 : return m_osFilename;
11997 : }
11998 :
11999 : const std::vector<std::shared_ptr<GDALDimension>> &
12000 99 : GetDimensions() const override
12001 : {
12002 99 : return m_dims;
12003 : }
12004 :
12005 38 : const GDALExtendedDataType &GetDataType() const override
12006 : {
12007 38 : return m_dt;
12008 : }
12009 :
12010 5 : const std::string &GetUnit() const override
12011 : {
12012 5 : return m_osUnit;
12013 : }
12014 :
12015 5 : const void *GetRawNoDataValue() const override
12016 : {
12017 5 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12018 : }
12019 :
12020 5 : double GetOffset(bool *pbHasOffset,
12021 : GDALDataType *peStorageType) const override
12022 : {
12023 5 : double dfRes = 0;
12024 5 : int bHasOffset = false;
12025 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12026 5 : if (poFirstBand) // to avoid -Wnull-dereference
12027 : {
12028 5 : dfRes = poFirstBand->GetOffset(&bHasOffset);
12029 7 : for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12030 : {
12031 : const double dfOtherRes =
12032 2 : m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12033 2 : bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12034 : }
12035 : }
12036 5 : if (pbHasOffset)
12037 5 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12038 5 : if (peStorageType)
12039 3 : *peStorageType = GDT_Unknown;
12040 5 : return dfRes;
12041 : }
12042 :
12043 5 : double GetScale(bool *pbHasScale,
12044 : GDALDataType *peStorageType) const override
12045 : {
12046 5 : double dfRes = 0;
12047 5 : int bHasScale = false;
12048 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12049 5 : if (poFirstBand) // to avoid -Wnull-dereference
12050 : {
12051 5 : dfRes = poFirstBand->GetScale(&bHasScale);
12052 7 : for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12053 : {
12054 : const double dfOtherRes =
12055 2 : m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12056 2 : bHasScale = bHasScale && (dfOtherRes == dfRes);
12057 : }
12058 : }
12059 5 : if (pbHasScale)
12060 5 : *pbHasScale = CPL_TO_BOOL(bHasScale);
12061 5 : if (peStorageType)
12062 3 : *peStorageType = GDT_Unknown;
12063 5 : return dfRes;
12064 : }
12065 :
12066 9 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12067 : {
12068 9 : auto poSrcSRS = m_poDS->GetSpatialRef();
12069 9 : if (!poSrcSRS)
12070 1 : return nullptr;
12071 16 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12072 :
12073 16 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12074 24 : for (auto &m : axisMapping)
12075 : {
12076 16 : if (m == 1)
12077 8 : m = m_iXDim + 1;
12078 8 : else if (m == 2)
12079 8 : m = m_iYDim + 1;
12080 : else
12081 0 : m = 0;
12082 : }
12083 8 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12084 8 : return poSRS;
12085 : }
12086 :
12087 7 : std::vector<GUInt64> GetBlockSize() const override
12088 : {
12089 7 : int nBlockXSize = 0;
12090 7 : int nBlockYSize = 0;
12091 7 : m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12092 7 : if (m_iBandDim == 0)
12093 : {
12094 6 : return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12095 6 : static_cast<GUInt64>(nBlockXSize)};
12096 : }
12097 : else
12098 : {
12099 1 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12100 1 : static_cast<GUInt64>(nBlockXSize), 1};
12101 : }
12102 : }
12103 :
12104 : std::vector<std::shared_ptr<GDALAttribute>>
12105 7 : GetAttributes(CSLConstList) const override
12106 : {
12107 7 : std::vector<std::shared_ptr<GDALAttribute>> res;
12108 7 : auto papszMD = m_poDS->GetMetadata();
12109 14 : for (auto iter = papszMD; iter && iter[0]; ++iter)
12110 : {
12111 7 : char *pszKey = nullptr;
12112 7 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12113 7 : if (pszKey && pszValue)
12114 : {
12115 : res.emplace_back(
12116 7 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12117 : }
12118 7 : CPLFree(pszKey);
12119 : }
12120 7 : return res;
12121 : }
12122 : };
12123 :
12124 10 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12125 : const size_t *count, const GInt64 *arrayStep,
12126 : const GPtrDiff_t *bufferStride,
12127 : const GDALExtendedDataType &bufferDataType,
12128 : void *pDstBuffer) const
12129 : {
12130 10 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12131 10 : bufferDataType, pDstBuffer);
12132 : }
12133 :
12134 : /************************************************************************/
12135 : /* ReadWrite() */
12136 : /************************************************************************/
12137 :
12138 11 : bool GDALMDArrayFromDataset::ReadWrite(
12139 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12140 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12141 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12142 : {
12143 11 : const auto eDT(bufferDataType.GetNumericDataType());
12144 11 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12145 11 : const int nX =
12146 11 : arrayStep[m_iXDim] > 0
12147 11 : ? static_cast<int>(arrayStartIdx[m_iXDim])
12148 0 : : static_cast<int>(arrayStartIdx[m_iXDim] -
12149 0 : (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12150 11 : const int nY =
12151 11 : arrayStep[m_iYDim] > 0
12152 11 : ? static_cast<int>(arrayStartIdx[m_iYDim])
12153 1 : : static_cast<int>(arrayStartIdx[m_iYDim] -
12154 1 : (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12155 11 : const int nSizeX =
12156 11 : static_cast<int>(count[m_iXDim] * ABS(arrayStep[m_iXDim]));
12157 11 : const int nSizeY =
12158 11 : static_cast<int>(count[m_iYDim] * ABS(arrayStep[m_iYDim]));
12159 11 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12160 11 : int nStrideXSign = 1;
12161 11 : if (arrayStep[m_iXDim] < 0)
12162 : {
12163 0 : pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12164 0 : nStrideXSign = -1;
12165 : }
12166 11 : int nStrideYSign = 1;
12167 11 : if (arrayStep[m_iYDim] < 0)
12168 : {
12169 1 : pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12170 1 : nStrideYSign = -1;
12171 : }
12172 11 : const GSpacing nPixelSpace =
12173 11 : static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12174 11 : const GSpacing nLineSpace =
12175 11 : static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12176 11 : const GSpacing nBandSpace =
12177 11 : static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12178 11 : std::vector<int> anBandList;
12179 28 : for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12180 17 : anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12181 17 : i * static_cast<int>(arrayStep[m_iBandDim]));
12182 :
12183 33 : return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12184 11 : static_cast<int>(count[m_iXDim]),
12185 11 : static_cast<int>(count[m_iYDim]), eDT,
12186 11 : static_cast<int>(count[m_iBandDim]),
12187 11 : anBandList.data(), nPixelSpace, nLineSpace,
12188 22 : nBandSpace, nullptr) == CE_None;
12189 : }
12190 :
12191 : /************************************************************************/
12192 : /* AsMDArray() */
12193 : /************************************************************************/
12194 :
12195 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12196 : *
12197 : * If this dataset is not already marked as shared, it will be, so that the
12198 : * returned array holds a reference to it.
12199 : *
12200 : * If the dataset has a geotransform attached, the X and Y dimensions of the
12201 : * returned array will have an associated indexing variable.
12202 : *
12203 : * The currently supported list of options is:
12204 : * <ul>
12205 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12206 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
12207 : * and the last (fastest changing direction) is X
12208 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
12209 : * and the last (fastest changing direction) is Band.
12210 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12211 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12212 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12213 : * "Y,X,Band" is use.
12214 : * </li>
12215 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
12216 : * item from which to build the band indexing variable.
12217 : * <ul>
12218 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12219 : * <li>"{None}" means that no band indexing variable must be created.</li>
12220 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
12221 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12222 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
12223 : * </ul>
12224 : * </li>
12225 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12226 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12227 : * Defaults to String.
12228 : * </li>
12229 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
12230 : * Defaults to "Band".
12231 : * </li>
12232 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
12233 : * </li>
12234 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
12235 : * </li>
12236 : * </ul>
12237 : *
12238 : * This is the same as the C function GDALDatasetAsMDArray().
12239 : *
12240 : * The "reverse" method is GDALMDArray::AsClassicDataset().
12241 : *
12242 : * @param papszOptions Null-terminated list of strings, or nullptr.
12243 : * @return a new array, or nullptr.
12244 : *
12245 : * @since GDAL 3.12
12246 : */
12247 18 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12248 : {
12249 18 : if (!GetShared())
12250 : {
12251 17 : MarkAsShared();
12252 : }
12253 18 : if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12254 : {
12255 1 : ReportError(
12256 : CE_Failure, CPLE_AppDefined,
12257 : "Degenerated array (band, Y and/or X dimension of size zero)");
12258 1 : return nullptr;
12259 : }
12260 17 : const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12261 30 : for (int i = 1; i < nBands; ++i)
12262 : {
12263 14 : if (eDT != papoBands[i]->GetRasterDataType())
12264 : {
12265 1 : ReportError(CE_Failure, CPLE_AppDefined,
12266 : "Non-uniform data type amongst bands");
12267 1 : return nullptr;
12268 : }
12269 : }
12270 : const char *pszDimOrder =
12271 16 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12272 16 : if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12273 2 : !EQUAL(pszDimOrder, "Y,X,Band"))
12274 : {
12275 1 : ReportError(CE_Failure, CPLE_IllegalArg,
12276 : "Illegal value for DIM_ORDER option");
12277 1 : return nullptr;
12278 : }
12279 15 : return GDALMDArrayFromDataset::Create(this, papszOptions);
12280 : }
12281 :
12282 : /************************************************************************/
12283 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12284 : /************************************************************************/
12285 :
12286 : /**
12287 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12288 :
12289 : The covariance indicates the level to which two bands vary together.
12290 :
12291 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12292 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12293 :
12294 : \f[
12295 : \mathrm{cov}[i,j] =
12296 : \frac{
12297 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12298 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12299 : }{
12300 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12301 : }
12302 : \f]
12303 :
12304 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12305 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12306 : is symmetric.
12307 :
12308 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12309 : if the pixels in bands are considered to be a sample of the whole population.
12310 : This is consistent with the default of
12311 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12312 : matrix is consistent with what can be obtained with
12313 :
12314 : \verbatim embed:rst
12315 : .. code-block:: python
12316 :
12317 : numpy.cov(
12318 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12319 : )
12320 : \endverbatim
12321 :
12322 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12323 : to be the whole population.
12324 :
12325 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12326 : this method uses them.
12327 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12328 : Otherwise, if bForce is false, an empty vector is returned
12329 :
12330 : @param nBandCount Zero for all bands, or number of values in panBandList.
12331 : Defaults to 0.
12332 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12333 : nBandCount values such as panBandList[i] is the index
12334 : between 1 and GetRasterCount() of a band that must be used
12335 : in the covariance computation. Defaults to nullptr.
12336 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12337 : ComputeInterBandCovarianceMatrix().
12338 : Defaults to false.
12339 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12340 : when the STATISTICS_COVARIANCES metadata items are missing.
12341 : Defaults to false.
12342 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12343 : write STATISTICS_COVARIANCES band metadata items.
12344 : Defaults to true.
12345 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12346 : averaging phase of the covariance computation.
12347 : Defaults to 1.
12348 : @param pfnProgress a function to call to report progress, or NULL.
12349 : @param pProgressData application data to pass to the progress function.
12350 :
12351 : @return a vector of nBandCount * nBandCount values if successful,
12352 : in row-major order, or an empty vector in case of failure
12353 :
12354 : @since 3.13
12355 :
12356 : @see ComputeInterBandCovarianceMatrix()
12357 : */
12358 :
12359 0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12360 : int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12361 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12362 : GDALProgressFunc pfnProgress, void *pProgressData)
12363 : {
12364 0 : std::vector<double> res;
12365 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12366 0 : if (nBandCountToUse == 0)
12367 0 : return res;
12368 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12369 : {
12370 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12371 : if (static_cast<uint32_t>(nBandCountToUse) >
12372 : std::numeric_limits<uint16_t>::max())
12373 : {
12374 : CPLError(CE_Failure, CPLE_OutOfMemory,
12375 : "Not enough memory to store result");
12376 : return res;
12377 : }
12378 : }
12379 : try
12380 : {
12381 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12382 : }
12383 0 : catch (const std::exception &)
12384 : {
12385 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12386 : "Not enough memory to store result");
12387 0 : return res;
12388 : }
12389 :
12390 0 : if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12391 : panBandList, bApproxOK, bForce,
12392 : bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12393 0 : pfnProgress, pProgressData) != CE_None)
12394 : {
12395 0 : res.clear();
12396 : }
12397 0 : return res;
12398 : }
12399 :
12400 : /************************************************************************/
12401 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12402 : /************************************************************************/
12403 :
12404 : /**
12405 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12406 :
12407 : The covariance indicates the level to which two bands vary together.
12408 :
12409 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12410 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12411 :
12412 : \f[
12413 : \mathrm{cov}[i,j] =
12414 : \frac{
12415 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12416 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12417 : }{
12418 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12419 : }
12420 : \f]
12421 :
12422 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12423 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12424 : is symmetric.
12425 :
12426 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12427 : if the pixels in bands are considered to be a sample of the whole population.
12428 : This is consistent with the default of
12429 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12430 : matrix is consistent with what can be obtained with
12431 :
12432 : \verbatim embed:rst
12433 : .. code-block:: python
12434 :
12435 : numpy.cov(
12436 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12437 : )
12438 : \endverbatim
12439 :
12440 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12441 : to be the whole population.
12442 :
12443 : The caller must provide an already allocated array in padfCovMatrix of size
12444 : at least nBandCount * nBandCount.
12445 :
12446 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12447 : this method uses them.
12448 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12449 : Otherwise, if bForce is false, an empty vector is returned
12450 :
12451 : This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12452 :
12453 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12454 : nBandCount * nBandCount.
12455 : @param nSize Number of elements in output array.
12456 : @param nBandCount Zero for all bands, or number of values in panBandList.
12457 : Defaults to 0.
12458 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12459 : nBandCount values such as panBandList[i] is the index
12460 : between 1 and GetRasterCount() of a band that must be used
12461 : in the covariance computation. Defaults to nullptr.
12462 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12463 : ComputeInterBandCovarianceMatrix().
12464 : Defaults to false.
12465 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12466 : when the STATISTICS_COVARIANCES metadata items are missing.
12467 : Defaults to false.
12468 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12469 : write STATISTICS_COVARIANCES band metadata items.
12470 : Defaults to true.
12471 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12472 : averaging phase of the covariance computation.
12473 : Defaults to 1.
12474 : @param pfnProgress a function to call to report progress, or NULL.
12475 : @param pProgressData application data to pass to the progress function.
12476 :
12477 : @return CE_None if successful, CE_Warning if values are not available in
12478 : metadata and bForce is false, or CE_Failure in case of failure
12479 :
12480 : @since 3.13
12481 :
12482 : @see ComputeInterBandCovarianceMatrix()
12483 : */
12484 :
12485 11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12486 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12487 : bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12488 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12489 : void *pProgressData)
12490 : {
12491 22 : std::vector<int> anBandListTmp; // keep in this scope
12492 11 : if (nBandCount == 0)
12493 : {
12494 0 : if (nBands == 0)
12495 0 : return CE_None;
12496 0 : for (int i = 0; i < nBands; ++i)
12497 0 : anBandListTmp.push_back(i + 1);
12498 0 : nBandCount = nBands;
12499 0 : panBandList = anBandListTmp.data();
12500 : }
12501 : else
12502 : {
12503 11 : if (nBandCount > nBands)
12504 : {
12505 1 : CPLError(CE_Failure, CPLE_AppDefined,
12506 : "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12507 1 : return CE_Failure;
12508 : }
12509 29 : for (int i = 0; i < nBandCount; ++i)
12510 : {
12511 21 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
12512 : {
12513 2 : CPLError(CE_Failure, CPLE_AppDefined,
12514 : "GetInterBandCovarianceMatrix(): invalid value "
12515 : "panBandList[%d] = %d",
12516 2 : i, panBandList[i]);
12517 2 : return CE_Failure;
12518 : }
12519 : }
12520 : }
12521 :
12522 8 : if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12523 : {
12524 0 : CPLError(
12525 : CE_Failure, CPLE_AppDefined,
12526 : "GetInterBandCovarianceMatrix(): too small result matrix provided");
12527 0 : return CE_Failure;
12528 : }
12529 8 : bool bGotFromMD = true;
12530 8 : size_t resIdx = 0;
12531 20 : for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12532 : {
12533 24 : const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12534 12 : "STATISTICS_COVARIANCES");
12535 12 : bGotFromMD = pszCov != nullptr;
12536 12 : if (bGotFromMD)
12537 : {
12538 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12539 6 : bGotFromMD = aosTokens.size() == nBands;
12540 6 : if (bGotFromMD)
12541 : {
12542 24 : for (int j = 0; j < nBandCount; ++j)
12543 18 : padfCovMatrix[resIdx++] =
12544 18 : CPLAtof(aosTokens[panBandList[j] - 1]);
12545 : }
12546 : }
12547 : }
12548 8 : if (bGotFromMD)
12549 2 : return CE_None;
12550 :
12551 6 : if (!bForce)
12552 1 : return CE_Warning;
12553 5 : return ComputeInterBandCovarianceMatrix(
12554 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12555 5 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12556 : }
12557 :
12558 : /************************************************************************/
12559 : /* GDALDatasetGetInterBandCovarianceMatrix() */
12560 : /************************************************************************/
12561 :
12562 : /**
12563 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12564 :
12565 : The covariance indicates the level to which two bands vary together.
12566 :
12567 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12568 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12569 :
12570 : \f[
12571 : \mathrm{cov}[i,j] =
12572 : \frac{
12573 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12574 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12575 : }{
12576 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12577 : }
12578 : \f]
12579 :
12580 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12581 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12582 : is symmetric.
12583 :
12584 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12585 : if the pixels in bands are considered to be a sample of the whole population.
12586 : This is consistent with the default of
12587 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12588 : matrix is consistent with what can be obtained with
12589 :
12590 : \verbatim embed:rst
12591 : .. code-block:: python
12592 :
12593 : numpy.cov(
12594 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12595 : )
12596 : \endverbatim
12597 :
12598 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12599 : to be the whole population.
12600 :
12601 : The caller must provide an already allocated array in padfCovMatrix of size
12602 : at least nBandCount * nBandCount.
12603 :
12604 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12605 : this method uses them.
12606 : Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12607 : Otherwise, if bForce is false, an empty vector is returned
12608 :
12609 : This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12610 :
12611 : @param hDS Dataset handle.
12612 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12613 : nBandCount * nBandCount.
12614 : @param nSize Number of elements in output array.
12615 : @param nBandCount Zero for all bands, or number of values in panBandList.
12616 : Defaults to 0.
12617 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12618 : nBandCount values such as panBandList[i] is the index
12619 : between 1 and GetRasterCount() of a band that must be used
12620 : in the covariance computation. Defaults to nullptr.
12621 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12622 : GDALDatasetComputeInterBandCovarianceMatrix().
12623 : Defaults to false.
12624 : @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12625 : when the STATISTICS_COVARIANCES metadata items are missing.
12626 : Defaults to false.
12627 : @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12628 : write STATISTICS_COVARIANCES band metadata items.
12629 : Defaults to true.
12630 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12631 : averaging phase of the covariance computation.
12632 : Defaults to 1.
12633 : @param pfnProgress a function to call to report progress, or NULL.
12634 : @param pProgressData application data to pass to the progress function.
12635 :
12636 : @return CE_None if successful, CE_Warning if values are not available in
12637 : metadata and bForce is false, or CE_Failure in case of failure
12638 :
12639 : @since 3.13
12640 :
12641 : @see GDALDatasetComputeInterBandCovarianceMatrix()
12642 : */
12643 11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12644 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12645 : const int *panBandList, bool bApproxOK, bool bForce,
12646 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12647 : GDALProgressFunc pfnProgress, void *pProgressData)
12648 : {
12649 11 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12650 11 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12651 11 : return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12652 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12653 11 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12654 : }
12655 :
12656 : /************************************************************************/
12657 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
12658 : /************************************************************************/
12659 :
12660 : /**
12661 : \brief Compute the covariance matrix between bands of this dataset.
12662 :
12663 : The covariance indicates the level to which two bands vary together.
12664 :
12665 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12666 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12667 :
12668 : \f[
12669 : \mathrm{cov}[i,j] =
12670 : \frac{
12671 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12672 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12673 : }{
12674 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12675 : }
12676 : \f]
12677 :
12678 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12679 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12680 : is symmetric.
12681 :
12682 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12683 : if the pixels in bands are considered to be a sample of the whole population.
12684 : This is consistent with the default of
12685 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12686 : matrix is consistent with what can be obtained with
12687 :
12688 : \verbatim embed:rst
12689 : .. code-block:: python
12690 :
12691 : numpy.cov(
12692 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12693 : )
12694 : \endverbatim
12695 :
12696 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12697 : to be the whole population.
12698 :
12699 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12700 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
12701 : to use them.
12702 :
12703 : @param nBandCount Zero for all bands, or number of values in panBandList.
12704 : Defaults to 0.
12705 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12706 : nBandCount values such as panBandList[i] is the index
12707 : between 1 and GetRasterCount() of a band that must be used
12708 : in the covariance computation. Defaults to nullptr.
12709 : @param bApproxOK Whether it is acceptable to use a subsample of values.
12710 : Defaults to false.
12711 : @param bWriteIntoMetadata Whether this method must write
12712 : STATISTICS_COVARIANCES band metadata items.
12713 : Defaults to true.
12714 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12715 : averaging phase of the covariance computation.
12716 : Defaults to 1.
12717 : @param pfnProgress a function to call to report progress, or NULL.
12718 : @param pProgressData application data to pass to the progress function.
12719 :
12720 : @return a vector of nBandCount * nBandCount values if successful,
12721 : in row-major order, or an empty vector in case of failure
12722 :
12723 : @since 3.13
12724 :
12725 : @see GetInterBandCovarianceMatrix()
12726 : */
12727 0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12728 : int nBandCount, const int *panBandList, bool bApproxOK,
12729 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12730 : GDALProgressFunc pfnProgress, void *pProgressData)
12731 : {
12732 0 : std::vector<double> res;
12733 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12734 0 : if (nBandCountToUse == 0)
12735 0 : return res;
12736 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12737 : {
12738 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12739 : if (static_cast<uint32_t>(nBandCountToUse) >
12740 : std::numeric_limits<uint16_t>::max())
12741 : {
12742 : CPLError(CE_Failure, CPLE_OutOfMemory,
12743 : "Not enough memory to store result");
12744 : return res;
12745 : }
12746 : }
12747 : try
12748 : {
12749 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12750 : }
12751 0 : catch (const std::exception &)
12752 : {
12753 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12754 : "Not enough memory to store result");
12755 0 : return res;
12756 : }
12757 :
12758 0 : if (ComputeInterBandCovarianceMatrix(
12759 : res.data(), res.size(), nBandCount, panBandList, bApproxOK,
12760 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
12761 0 : pProgressData) != CE_None)
12762 0 : res.clear();
12763 0 : return res;
12764 : }
12765 :
12766 : /************************************************************************/
12767 : /* ComputeInterBandCovarianceMatrixInternal() */
12768 : /************************************************************************/
12769 :
12770 : template <class T>
12771 : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
12772 : // causes that to happen
12773 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
12774 15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
12775 : double *padfCovMatrix, int nBandCount,
12776 : const int *panBandList,
12777 : GDALRasterBand *const *papoBands,
12778 : int nDeltaDegreeOfFreedom,
12779 : GDALProgressFunc pfnProgress,
12780 : void *pProgressData)
12781 : {
12782 : // We use the padfCovMatrix to accumulate co-moments
12783 : // Dimension = nBandCount * nBandCount
12784 15 : double *const padfComomentMatrix = padfCovMatrix;
12785 :
12786 : // Matrix of nBandCount * nBandCount storing co-moments, in optimized
12787 : // case when the block has no nodata value
12788 : // Only used if T != double
12789 30 : [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
12790 :
12791 : // Count number of valid values in padfComomentMatrix for each (i,j) tuple
12792 : // Updated while iterating over blocks
12793 : // Dimension = nBandCount * nBandCount
12794 30 : std::vector<uint64_t> anCount;
12795 :
12796 : // Mean of bands, for each (i,j) tuple.
12797 : // Updated while iterating over blocks.
12798 : // This is a matrix rather than a vector due to the fact when need to update
12799 : // it in sync with padfComomentMatrix
12800 : // Dimension = nBandCount * nBandCount
12801 30 : std::vector<T> adfMean;
12802 :
12803 : // Number of valid values when computing adfMean, for each (i,j) tuple.
12804 : // Updated while iterating over blocks.
12805 : // This is a matrix rather than a vector due to the fact when need to update
12806 : // it in sync with padfComomentMatrix
12807 : // Dimension = nBandCount * nBandCount
12808 30 : std::vector<uint64_t> anCountMean;
12809 :
12810 : // Mean of values for each band i. Refreshed for each block.
12811 : // Dimension = nBandCount
12812 30 : std::vector<T> adfCurBlockMean;
12813 :
12814 : // Number of values participating to the mean for each band i.
12815 : // Refreshed for each block. Dimension = nBandCount
12816 30 : std::vector<size_t> anCurBlockCount;
12817 :
12818 : // Pixel values for all selected values for the current block
12819 : // Dimension = nBlockXSize * nBlockYSize * nBandCount
12820 30 : std::vector<T> adfCurBlockPixelsAllBands;
12821 :
12822 : // Vector of nodata values for all bands. Dimension = nBandCount
12823 30 : std::vector<T> adfNoData;
12824 :
12825 : // Vector of mask bands for all bands. Dimension = nBandCount
12826 30 : std::vector<GDALRasterBand *> apoMaskBands;
12827 :
12828 : // Vector of vector of mask values. Dimension = nBandCount
12829 30 : std::vector<std::vector<GByte>> aabyCurBlockMask;
12830 :
12831 : // Vector of pointer to vector of mask values. Dimension = nBandCount
12832 30 : std::vector<std::vector<GByte> *> pabyCurBlockMask;
12833 :
12834 15 : int nBlockXSize = 0;
12835 15 : int nBlockYSize = 0;
12836 15 : papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
12837 :
12838 30 : if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
12839 15 : std::numeric_limits<size_t>::max() / nBandCount)
12840 : {
12841 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
12842 : "Not enough memory for intermediate computations");
12843 0 : return CE_Failure;
12844 : }
12845 15 : const size_t nPixelsInBlock =
12846 15 : static_cast<size_t>(nBlockXSize) * nBlockYSize;
12847 :
12848 : // Allocate temporary matrices and vectors
12849 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
12850 :
12851 : using MySignedSize_t = std::make_signed_t<size_t>;
12852 15 : const auto kMax =
12853 15 : static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
12854 30 : std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
12855 : try
12856 : {
12857 15 : anCount.resize(nMatrixSize);
12858 15 : adfMean.resize(nMatrixSize);
12859 15 : anCountMean.resize(nMatrixSize);
12860 :
12861 : if constexpr (!std::is_same_v<T, double>)
12862 : {
12863 : aCurBlockComomentMatrix.resize(nMatrixSize);
12864 : }
12865 :
12866 15 : anMapLinearIdxToIJ.resize(kMax);
12867 :
12868 15 : adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
12869 :
12870 15 : adfCurBlockMean.resize(nBandCount);
12871 15 : anCurBlockCount.resize(nBandCount);
12872 15 : adfNoData.resize(nBandCount);
12873 15 : apoMaskBands.resize(nBandCount);
12874 15 : aabyCurBlockMask.resize(nBandCount);
12875 15 : pabyCurBlockMask.resize(nBandCount);
12876 : }
12877 0 : catch (const std::exception &)
12878 : {
12879 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
12880 : "Not enough memory for intermediate computations");
12881 0 : return CE_Failure;
12882 : }
12883 :
12884 15 : constexpr T ZERO{0};
12885 15 : std::fill(padfComomentMatrix,
12886 15 : padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
12887 15 : 0);
12888 :
12889 : {
12890 15 : MySignedSize_t nLinearIdx = 0;
12891 1045 : for (int i = 0; i < nBandCount; ++i)
12892 : {
12893 501581 : for (int j = i; j < nBandCount; ++j)
12894 : {
12895 500551 : anMapLinearIdxToIJ[nLinearIdx] = {i, j};
12896 500551 : ++nLinearIdx;
12897 : }
12898 : }
12899 : }
12900 :
12901 : // Fetch nodata values and mask bands
12902 15 : bool bAllBandsSameMask = false;
12903 15 : bool bIsAllInteger = false;
12904 15 : bool bNoneHasMaskOrNodata = false;
12905 1045 : for (int i = 0; i < nBandCount; ++i)
12906 : {
12907 1030 : const auto poBand = papoBands[panBandList[i] - 1];
12908 2057 : bIsAllInteger = (i == 0 || bIsAllInteger) &&
12909 1027 : GDALDataTypeIsInteger(poBand->GetRasterDataType());
12910 1030 : int bHasNoData = FALSE;
12911 1030 : double dfNoData = poBand->GetNoDataValue(&bHasNoData);
12912 1030 : if (!bHasNoData)
12913 : {
12914 1028 : dfNoData = std::numeric_limits<double>::quiet_NaN();
12915 :
12916 1032 : if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
12917 4 : poBand->GetColorInterpretation() != GCI_AlphaBand)
12918 : {
12919 4 : apoMaskBands[i] = poBand->GetMaskBand();
12920 : try
12921 : {
12922 4 : aabyCurBlockMask[i].resize(nPixelsInBlock);
12923 : }
12924 0 : catch (const std::exception &)
12925 : {
12926 0 : poDS->ReportError(
12927 : CE_Failure, CPLE_OutOfMemory,
12928 : "Not enough memory for intermediate computations");
12929 0 : return CE_Failure;
12930 : }
12931 : // coverity[escape]
12932 4 : pabyCurBlockMask[i] = &aabyCurBlockMask[i];
12933 : }
12934 : }
12935 1030 : adfNoData[i] = static_cast<T>(dfNoData);
12936 1030 : if (i == 0)
12937 15 : bAllBandsSameMask = (apoMaskBands[0] != nullptr);
12938 1015 : else if (bAllBandsSameMask)
12939 2 : bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
12940 :
12941 3072 : bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
12942 3072 : std::isnan(dfNoData) &&
12943 1026 : apoMaskBands[i] == nullptr;
12944 : }
12945 15 : if (bAllBandsSameMask)
12946 : {
12947 2 : for (int i = 1; i < nBandCount; ++i)
12948 : {
12949 1 : apoMaskBands[i] = nullptr;
12950 1 : aabyCurBlockMask[i].clear();
12951 1 : pabyCurBlockMask[i] = pabyCurBlockMask[0];
12952 : }
12953 : }
12954 :
12955 15 : const auto nIterCount =
12956 : static_cast<uint64_t>(
12957 15 : cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
12958 15 : cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
12959 15 : uint64_t nCurIter = 0;
12960 :
12961 15 : int nNumThreads = 1;
12962 : #ifdef HAVE_OPENMP
12963 15 : if (nBandCount >= 100)
12964 : {
12965 1 : const int nNumCPUs = CPLGetNumCPUs();
12966 1 : nNumThreads = std::max(1, nNumCPUs / 2);
12967 : const char *pszThreads =
12968 1 : CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
12969 1 : if (pszThreads && !EQUAL(pszThreads, "ALL_CPUS"))
12970 : {
12971 0 : nNumThreads = std::clamp(atoi(pszThreads), 1, nNumCPUs);
12972 : }
12973 : }
12974 : #endif
12975 :
12976 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
12977 30 : const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
12978 30 : __builtin_cpu_supports("avx2") &&
12979 : __builtin_cpu_supports("fma");
12980 : #endif
12981 :
12982 : // Iterate over all blocks
12983 77 : for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
12984 : {
12985 32 : const auto nThisBlockPixelCount =
12986 32 : static_cast<size_t>(window.nXSize) * window.nYSize;
12987 :
12988 : // Extract pixel values and masks
12989 96 : CPLErr eErr = poDS->RasterIO(
12990 32 : GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
12991 32 : adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
12992 : gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
12993 : nullptr);
12994 32 : if (eErr == CE_None && bAllBandsSameMask)
12995 : {
12996 2 : eErr = apoMaskBands[0]->RasterIO(
12997 1 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
12998 1 : window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
12999 1 : window.nYSize, GDT_Byte, 0, 0, nullptr);
13000 : }
13001 : else
13002 : {
13003 1108 : for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13004 : {
13005 1077 : if (apoMaskBands[i])
13006 : {
13007 4 : eErr = apoMaskBands[i]->RasterIO(
13008 2 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13009 2 : window.nYSize, aabyCurBlockMask[i].data(),
13010 2 : window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13011 : }
13012 : }
13013 : }
13014 32 : if (eErr != CE_None)
13015 1 : return eErr;
13016 :
13017 : // Compute the mean of all bands for this block
13018 32 : bool bAllBandsAreAllNodata = false;
13019 32 : bool bNoBandHasNodata = false;
13020 1111 : for (int i = 0; i < nBandCount; ++i)
13021 : {
13022 1079 : T dfSum = 0;
13023 1079 : size_t nCount = 0;
13024 1079 : const T dfNoDataI = adfNoData[i];
13025 1079 : const T *padfI =
13026 1079 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13027 : #ifdef HAVE_OPENMP_SIMD
13028 1079 : #pragma omp simd reduction(+ : dfSum)
13029 : #endif
13030 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13031 : {
13032 822482 : const T dfI = padfI[iPixel];
13033 822482 : const bool bIsValid =
13034 1644950 : !std::isnan(dfI) && dfI != dfNoDataI &&
13035 822466 : (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13036 822482 : nCount += bIsValid;
13037 822482 : dfSum += bIsValid ? dfI : ZERO;
13038 : }
13039 1079 : adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13040 1079 : anCurBlockCount[i] = nCount;
13041 1079 : bAllBandsAreAllNodata =
13042 1079 : (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13043 1079 : bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13044 : (nCount == nThisBlockPixelCount);
13045 : }
13046 :
13047 : // Modify the pixel values to shift them by minus the mean
13048 32 : if (!bAllBandsAreAllNodata)
13049 : {
13050 1103 : for (int i = 0; i < nBandCount; ++i)
13051 : {
13052 1074 : T *padfI =
13053 1074 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13054 1074 : const T dfMeanI = adfCurBlockMean[i];
13055 823546 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13056 : {
13057 822472 : padfI[iPixel] -= dfMeanI;
13058 : }
13059 : }
13060 : }
13061 :
13062 : // Update padfComomentMatrix, anCount, adfMean, anCountMean
13063 : // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13064 32 : const auto UpdateGlobalValues =
13065 13507600 : [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13066 : &anCurBlockCount, padfComomentMatrix,
13067 : nBandCount](int i, int j, size_t nCount, T dfComoment)
13068 : {
13069 500647 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13070 500647 : const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13071 :
13072 : // Update the total comoment using last formula of paragraph
13073 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13074 : // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13075 : // (mean_I(A) - mean_I(B)) *
13076 : // (mean_J(A) - mean_J(B)) *
13077 : // (count(A) * count(B)) / (count(A) + count(B))
13078 : //
13079 : // There might be a small gotcha in the fact that the set of
13080 : // pixels on which the means are computed is not always the
13081 : // same as the the one on which the comoment is computed, if
13082 : // pixels are not valid/invalid at the same indices among bands
13083 : // It is not obvious (to me) what should be the correct behavior.
13084 : // The current approach has the benefit to avoid recomputing
13085 : // the mean for each (i,j) tuple, but only for all i.
13086 500647 : if (nCount > 0)
13087 : {
13088 500639 : padfComomentMatrix[idxInMatrixI] +=
13089 : static_cast<double>(dfComoment);
13090 500639 : padfComomentMatrix[idxInMatrixI] +=
13091 500639 : static_cast<double>(adfMean[idxInMatrixI] -
13092 500639 : adfCurBlockMean[i]) *
13093 500639 : static_cast<double>(adfMean[idxInMatrixJ] -
13094 500639 : adfCurBlockMean[j]) *
13095 500639 : (static_cast<double>(anCount[idxInMatrixI]) *
13096 500639 : static_cast<double>(nCount) /
13097 500639 : static_cast<double>(anCount[idxInMatrixI] + nCount));
13098 :
13099 500639 : anCount[idxInMatrixI] += nCount;
13100 : }
13101 :
13102 : // Update means
13103 500647 : if (anCurBlockCount[i] > 0)
13104 : {
13105 1001280 : adfMean[idxInMatrixI] +=
13106 500640 : (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13107 : static_cast<T>(
13108 500640 : static_cast<double>(anCurBlockCount[i]) /
13109 500640 : static_cast<double>(anCountMean[idxInMatrixI] +
13110 : anCurBlockCount[i]));
13111 :
13112 500640 : anCountMean[idxInMatrixI] += anCurBlockCount[i];
13113 : }
13114 :
13115 500647 : if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13116 : {
13117 999132 : adfMean[idxInMatrixJ] +=
13118 499566 : (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13119 : static_cast<T>(
13120 499566 : static_cast<double>(anCurBlockCount[j]) /
13121 499566 : static_cast<double>(anCountMean[idxInMatrixJ] +
13122 : anCurBlockCount[j]));
13123 :
13124 499566 : anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13125 : }
13126 : };
13127 :
13128 32 : if (bAllBandsAreAllNodata)
13129 : {
13130 : // Optimized code path where all values in the current block
13131 : // are invalid
13132 :
13133 8 : for (int i = 0; i < nBandCount; ++i)
13134 : {
13135 12 : for (int j = i; j < nBandCount; ++j)
13136 : {
13137 7 : UpdateGlobalValues(i, j, 0, ZERO);
13138 : }
13139 : }
13140 : }
13141 29 : else if (bNoBandHasNodata)
13142 : {
13143 : // Optimized code path where there are no invalid value in the
13144 : // current block
13145 :
13146 : if constexpr (!std::is_same_v<T, double>)
13147 : {
13148 : std::fill(aCurBlockComomentMatrix.begin(),
13149 : aCurBlockComomentMatrix.end(), ZERO);
13150 :
13151 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13152 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13153 : aCurBlockComomentMatrix.data(), nBandCount,
13154 : nThisBlockPixelCount);
13155 : }
13156 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13157 24 : else if (bHasAVX2_FMA)
13158 : {
13159 24 : GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13160 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13161 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13162 : }
13163 : #endif
13164 : else
13165 : {
13166 0 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13167 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13168 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13169 : }
13170 :
13171 1088 : for (int i = 0; i < nBandCount; ++i)
13172 : {
13173 501689 : for (int j = i; j < nBandCount; ++j)
13174 : {
13175 : if constexpr (!std::is_same_v<T, double>)
13176 : {
13177 : const auto idxInMatrixI =
13178 : static_cast<size_t>(i) * nBandCount + j;
13179 : UpdateGlobalValues(
13180 : i, j, nThisBlockPixelCount,
13181 : aCurBlockComomentMatrix[idxInMatrixI]);
13182 : }
13183 : else
13184 : {
13185 500625 : UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13186 : }
13187 : }
13188 : }
13189 : }
13190 : else
13191 : {
13192 : #ifdef HAVE_OPENMP
13193 5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
13194 : #endif
13195 : for (MySignedSize_t k = 0; k < kMax; ++k)
13196 : {
13197 : int i, j;
13198 : std::tie(i, j) = anMapLinearIdxToIJ[k];
13199 :
13200 : // Now compute the moment of (i, j), but just for this block
13201 : size_t nCount = 0;
13202 : T dfComoment = 0;
13203 : const T *padfI =
13204 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13205 : const T *padfJ =
13206 : adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13207 :
13208 : // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13209 : // for the current block
13210 : if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13211 : anCurBlockCount[j] == nThisBlockPixelCount) ||
13212 : (bNoneHasMaskOrNodata && bIsAllInteger))
13213 : {
13214 : // Most optimized code path: integer, no nodata, no mask
13215 : #ifdef HAVE_OPENMP_SIMD
13216 : #pragma omp simd reduction(+ : dfComoment)
13217 : #endif
13218 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13219 : ++iPixel)
13220 : {
13221 : dfComoment += padfI[iPixel] * padfJ[iPixel];
13222 : }
13223 : nCount = nThisBlockPixelCount;
13224 : }
13225 : else if (bNoneHasMaskOrNodata)
13226 : {
13227 : // Floating-point code path with no nodata and no mask
13228 : #ifdef HAVE_OPENMP_SIMD
13229 : #pragma omp simd reduction(+ : dfComoment)
13230 : #endif
13231 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13232 : ++iPixel)
13233 : {
13234 : const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13235 : const bool bIsValid = !std::isnan(dfAcc);
13236 : nCount += bIsValid;
13237 : dfComoment += bIsValid ? dfAcc : ZERO;
13238 : }
13239 : }
13240 : else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13241 : {
13242 : // Code path when there are both nodata values
13243 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13244 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13245 :
13246 : #ifdef HAVE_OPENMP_SIMD
13247 : #pragma omp simd reduction(+ : dfComoment)
13248 : #endif
13249 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13250 : ++iPixel)
13251 : {
13252 : const T dfI = padfI[iPixel];
13253 : const T dfJ = padfJ[iPixel];
13254 : const T dfAcc = dfI * dfJ;
13255 : const bool bIsValid = !std::isnan(dfAcc) &&
13256 : dfI != shiftedNoDataI &&
13257 : dfJ != shiftedNoDataJ;
13258 : nCount += bIsValid;
13259 : dfComoment += bIsValid ? dfAcc : ZERO;
13260 : }
13261 : }
13262 : else
13263 : {
13264 : // Generic code path
13265 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13266 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13267 :
13268 : #ifdef HAVE_OPENMP_SIMD
13269 : #pragma omp simd reduction(+ : dfComoment)
13270 : #endif
13271 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13272 : ++iPixel)
13273 : {
13274 : const T dfI = padfI[iPixel];
13275 : const T dfJ = padfJ[iPixel];
13276 : const T dfAcc = dfI * dfJ;
13277 : const bool bIsValid =
13278 : !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13279 : dfJ != shiftedNoDataJ &&
13280 : (!pabyCurBlockMask[i] ||
13281 : (*pabyCurBlockMask[i])[iPixel]) &&
13282 : (!pabyCurBlockMask[j] ||
13283 : (*pabyCurBlockMask[j])[iPixel]);
13284 : nCount += bIsValid;
13285 : dfComoment += bIsValid ? dfAcc : ZERO;
13286 : }
13287 : }
13288 :
13289 : UpdateGlobalValues(i, j, nCount, dfComoment);
13290 : }
13291 : }
13292 :
13293 32 : ++nCurIter;
13294 35 : if (pfnProgress &&
13295 3 : !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13296 : pProgressData))
13297 : {
13298 1 : poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13299 : "User terminated");
13300 1 : return CE_Failure;
13301 : }
13302 : }
13303 :
13304 : // Finalize by dividing co-moments by the number of contributing values
13305 : // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13306 44 : for (int i = 0; i < nBandCount; ++i)
13307 : {
13308 : // The covariance matrix is symmetric. So start at i
13309 81 : for (int j = i; j < nBandCount; ++j)
13310 : {
13311 51 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13312 51 : const double dfCovariance =
13313 51 : (nDeltaDegreeOfFreedom < 0 ||
13314 51 : anCount[idxInMatrixI] <=
13315 51 : static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13316 4 : ? std::numeric_limits<double>::quiet_NaN()
13317 94 : : padfComomentMatrix[idxInMatrixI] /
13318 47 : static_cast<double>(anCount[idxInMatrixI] -
13319 47 : nDeltaDegreeOfFreedom);
13320 :
13321 51 : padfCovMatrix[idxInMatrixI] = dfCovariance;
13322 : // Fill lower triangle
13323 51 : padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13324 : dfCovariance;
13325 : }
13326 : }
13327 :
13328 14 : return CE_None;
13329 : }
13330 :
13331 : /************************************************************************/
13332 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
13333 : /************************************************************************/
13334 :
13335 : /**
13336 : \brief Compute the covariance matrix between bands of this dataset.
13337 :
13338 : The covariance indicates the level to which two bands vary together.
13339 :
13340 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13341 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13342 :
13343 : \f[
13344 : \mathrm{cov}[i,j] =
13345 : \frac{
13346 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13347 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13348 : }{
13349 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13350 : }
13351 : \f]
13352 :
13353 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13354 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13355 : is symmetric.
13356 :
13357 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13358 : if the pixels in bands are considered to be a sample of the whole population.
13359 : This is consistent with the default of
13360 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13361 : matrix is consistent with what can be obtained with
13362 :
13363 : \verbatim embed:rst
13364 : .. code-block:: python
13365 :
13366 : numpy.cov(
13367 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13368 : )
13369 : \endverbatim
13370 :
13371 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13372 : to be the whole population.
13373 :
13374 : The caller must provide an already allocated array in padfCovMatrix of size
13375 : at least nBandCount * nBandCount.
13376 :
13377 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13378 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
13379 : to use them.
13380 :
13381 : The implementation is optimized to minimize the amount of pixel reading.
13382 :
13383 : This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13384 :
13385 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13386 : nBandCount * nBandCount.
13387 : @param nSize Number of elements in output array.
13388 : @param nBandCount Zero for all bands, or number of values in panBandList.
13389 : Defaults to 0.
13390 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13391 : nBandCount values such as panBandList[i] is the index
13392 : between 1 and GetRasterCount() of a band that must be used
13393 : in the covariance computation. Defaults to nullptr.
13394 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13395 : Defaults to false.
13396 : @param bWriteIntoMetadata Whether this method must write
13397 : STATISTICS_COVARIANCES band metadata items.
13398 : Defaults to true.
13399 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13400 : averaging phase of the covariance computation.
13401 : Defaults to 1.
13402 : @param pfnProgress a function to call to report progress, or NULL.
13403 : @param pProgressData application data to pass to the progress function.
13404 :
13405 : @return CE_None if successful, or CE_Failure in case of failure
13406 :
13407 : @since 3.13
13408 :
13409 : @see GetInterBandCovarianceMatrix()
13410 : */
13411 22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13412 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13413 : bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13414 : GDALProgressFunc pfnProgress, void *pProgressData)
13415 : {
13416 44 : std::vector<int> anBandListTmp; // keep in this scope
13417 22 : if (nBandCount == 0)
13418 : {
13419 0 : if (nBands == 0)
13420 0 : return CE_None;
13421 0 : for (int i = 0; i < nBands; ++i)
13422 0 : anBandListTmp.push_back(i + 1);
13423 0 : nBandCount = nBands;
13424 0 : panBandList = anBandListTmp.data();
13425 : }
13426 : else
13427 : {
13428 22 : if (nBandCount > nBands)
13429 : {
13430 1 : CPLError(CE_Failure, CPLE_AppDefined,
13431 : "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13432 1 : return CE_Failure;
13433 : }
13434 1057 : for (int i = 0; i < nBandCount; ++i)
13435 : {
13436 1038 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
13437 : {
13438 2 : CPLError(CE_Failure, CPLE_AppDefined,
13439 : "ComputeInterBandCovarianceMatrix(): invalid value "
13440 : "panBandList[%d] = %d",
13441 2 : i, panBandList[i]);
13442 2 : return CE_Failure;
13443 : }
13444 : }
13445 :
13446 19 : if (bWriteIntoMetadata)
13447 : {
13448 14 : bool bOK = nBandCount == nBands;
13449 38 : for (int i = 0; bOK && i < nBandCount; ++i)
13450 : {
13451 24 : bOK = (panBandList[i] == i + 1);
13452 : }
13453 14 : if (!bOK)
13454 : {
13455 4 : CPLError(CE_Failure, CPLE_AppDefined,
13456 : "ComputeInterBandCovarianceMatrix(): cannot write "
13457 : "STATISTICS_COVARIANCES metadata since the input band "
13458 : "list is not [1, 2, ... GetRasterCount()]");
13459 4 : return CE_Failure;
13460 : }
13461 : }
13462 : }
13463 :
13464 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13465 15 : if (nSize < nMatrixSize)
13466 : {
13467 0 : CPLError(CE_Failure, CPLE_AppDefined,
13468 : "ComputeInterBandCovarianceMatrix(): too small result matrix "
13469 : "provided");
13470 0 : return CE_Failure;
13471 : }
13472 :
13473 : // Find appropriate overview dataset
13474 15 : GDALDataset *poActiveDS = this;
13475 15 : if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13476 : {
13477 1 : GDALDataset *poOvrDS = nullptr;
13478 4 : for (int i = 0; i < nBandCount; ++i)
13479 : {
13480 3 : const int nIdxBand = panBandList[i] - 1;
13481 6 : auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13482 3 : GDALSTAT_APPROX_NUMSAMPLES);
13483 :
13484 6 : if (poOvrBand == papoBands[i] ||
13485 3 : poOvrBand->GetBand() != panBandList[i])
13486 : {
13487 0 : poOvrDS = nullptr;
13488 0 : break;
13489 : }
13490 3 : else if (i == 0)
13491 : {
13492 1 : if (poOvrBand->GetDataset() == this)
13493 : {
13494 0 : break;
13495 : }
13496 1 : poOvrDS = poOvrBand->GetDataset();
13497 : }
13498 2 : else if (poOvrBand->GetDataset() != poOvrDS)
13499 : {
13500 0 : poOvrDS = nullptr;
13501 0 : break;
13502 : }
13503 : }
13504 1 : if (poOvrDS)
13505 : {
13506 1 : poActiveDS = poOvrDS;
13507 : }
13508 : }
13509 :
13510 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13511 : const auto UseFloat32 = [](GDALDataType eDT)
13512 : {
13513 : return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13514 : eDT == GDT_Int16 || eDT == GDT_Float32;
13515 : };
13516 :
13517 : bool bUseFloat32 = UseFloat32(
13518 : poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13519 : for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13520 : {
13521 : bUseFloat32 = UseFloat32(
13522 : poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13523 : }
13524 : #endif
13525 :
13526 : CPLErr eErr =
13527 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13528 : bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13529 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13530 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13531 : pfnProgress, pProgressData)
13532 : :
13533 : #endif
13534 30 : ComputeInterBandCovarianceMatrixInternal<double>(
13535 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13536 15 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13537 : pfnProgress, pProgressData);
13538 :
13539 15 : if (bWriteIntoMetadata && eErr == CE_None)
13540 : {
13541 10 : CPLAssert(nBands == nBandCount);
13542 20 : std::string osStr;
13543 10 : size_t idx = 0;
13544 32 : for (int i = 0; i < nBands; ++i)
13545 : {
13546 22 : osStr.clear();
13547 74 : for (int j = 0; j < nBands; ++j, ++idx)
13548 : {
13549 52 : if (j > 0)
13550 30 : osStr += ',';
13551 52 : osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13552 : }
13553 22 : papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13554 22 : osStr.c_str());
13555 : }
13556 : }
13557 :
13558 15 : return eErr;
13559 : }
13560 :
13561 : /************************************************************************/
13562 : /* GDALDatasetComputeInterBandCovarianceMatrix() */
13563 : /************************************************************************/
13564 :
13565 : /**
13566 : \brief Compute the covariance matrix between bands of this dataset.
13567 :
13568 : The covariance indicates the level to which two bands vary together.
13569 :
13570 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13571 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13572 :
13573 : \f[
13574 : \mathrm{cov}[i,j] =
13575 : \frac{
13576 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13577 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13578 : }{
13579 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13580 : }
13581 : \f]
13582 :
13583 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13584 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13585 : is symmetric.
13586 :
13587 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13588 : if the pixels in bands are considered to be a sample of the whole population.
13589 : This is consistent with the default of
13590 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13591 : matrix is consistent with what can be obtained with
13592 :
13593 : \verbatim embed:rst
13594 : .. code-block:: python
13595 :
13596 : numpy.cov(
13597 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13598 : )
13599 : \endverbatim
13600 :
13601 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13602 : to be the whole population.
13603 :
13604 : The caller must provide an already allocated array in padfCovMatrix of size
13605 : at least GDALGetRasterCount() * GDALGetRasterCount().
13606 :
13607 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13608 : metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13609 : to use them.
13610 :
13611 : This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13612 :
13613 : @param hDS Dataset handle.
13614 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13615 : nBandCount * nBandCount.
13616 : @param nSize Number of elements in output array.
13617 : @param nBandCount Zero for all bands, or number of values in panBandList.
13618 : Defaults to 0.
13619 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13620 : nBandCount values such as panBandList[i] is the index
13621 : between 1 and GetRasterCount() of a band that must be used
13622 : in the covariance computation. Defaults to nullptr.
13623 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13624 : Defaults to false.
13625 : @param bWriteIntoMetadata Whether this method must write
13626 : STATISTICS_COVARIANCES band metadata items.
13627 : Defaults to true.
13628 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13629 : averaging phase of the covariance computation.
13630 : Defaults to 1.
13631 : @param pfnProgress a function to call to report progress, or NULL.
13632 : @param pProgressData application data to pass to the progress function.
13633 :
13634 : @return CE_None if successful, or CE_Failure in case of failure
13635 :
13636 : @since 3.13
13637 :
13638 : @see GDALDatasetGetInterBandCovarianceMatrix()
13639 : */
13640 17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13641 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13642 : const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13643 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13644 : void *pProgressData)
13645 : {
13646 17 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13647 17 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13648 17 : return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13649 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13650 17 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13651 : }
|