Coverage Report

Created: 2026-04-01 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdaldataset.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Base class for raster file formats.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1998, 2003, Frank Warmerdam
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
16
#include <algorithm>
17
#include <array>
18
#include <cassert>
19
#include <climits>
20
#include <cmath>
21
#include <cstdarg>
22
#include <cstdio>
23
#include <cstdlib>
24
#include <cstring>
25
#include <limits>
26
#include <map>
27
#include <mutex>
28
#include <new>
29
#include <set>
30
#include <string>
31
#include <type_traits>
32
#include <utility>
33
34
#include "cpl_conv.h"
35
#include "cpl_cpu_features.h"
36
#include "cpl_error.h"
37
#include "cpl_hash_set.h"
38
#include "cpl_multiproc.h"
39
#include "cpl_progress.h"
40
#include "cpl_string.h"
41
#include "cpl_vsi.h"
42
#include "cpl_vsi_error.h"
43
#include "cpl_vsi_virtual.h"
44
45
#include "gdal.h"
46
#include "gdal_alg.h"
47
#include "gdal_abstractbandblockcache.h"
48
#include "gdalantirecursion.h"
49
#include "gdal_dataset.h"
50
#include "gdal_matrix.hpp"
51
52
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
53
#include "gdal_matrix_avx2_fma.h"
54
#endif
55
56
#include "gdalsubdatasetinfo.h"
57
#include "gdal_thread_pool.h"
58
#include "gdal_typetraits.h"
59
60
#include "ogr_api.h"
61
#include "ogr_attrind.h"
62
#include "ogr_core.h"
63
#include "ogr_feature.h"
64
#include "ogr_featurestyle.h"
65
#include "ogr_gensql.h"
66
#include "ogr_geometry.h"
67
#include "ogr_p.h"
68
#include "ogr_spatialref.h"
69
#include "ogr_srs_api.h"
70
#include "ograpispy.h"
71
#include "ogrsf_frmts.h"
72
#include "ogrunionlayer.h"
73
#include "ogr_swq.h"
74
#include "memmultidim.h"
75
#include "gdalmultidim_priv.h"
76
77
#include "../frmts/derived/derivedlist.h"
78
79
#ifdef SQLITE_ENABLED
80
#include "../sqlite/ogrsqliteexecutesql.h"
81
#endif
82
83
#ifdef HAVE_OPENMP
84
#include <omp.h>
85
#endif
86
87
extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
88
89
enum class GDALAllowReadWriteMutexState
90
{
91
    RW_MUTEX_STATE_UNKNOWN,
92
    RW_MUTEX_STATE_ALLOWED,
93
    RW_MUTEX_STATE_DISABLED
94
};
95
96
const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
97
const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
98
99
class GDALDataset::Private
100
{
101
    CPL_DISALLOW_COPY_ASSIGN(Private)
102
103
  public:
104
    CPLMutex *hMutex = nullptr;
105
    std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
106
#ifdef DEBUG_EXTRA
107
    std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
108
#endif
109
    GDALAllowReadWriteMutexState eStateReadWriteMutex =
110
        GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
111
    int nCurrentLayerIdx = 0;
112
    int nLayerCount = -1;
113
    GIntBig nFeatureReadInLayer = 0;
114
    GIntBig nFeatureReadInDataset = 0;
115
    GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
116
    GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
117
    OGRLayer *poCurrentLayer = nullptr;
118
119
    std::mutex m_oMutexWKT{};
120
121
    char *m_pszWKTCached = nullptr;
122
    OGRSpatialReference *m_poSRSCached = nullptr;
123
    char *m_pszWKTGCPCached = nullptr;
124
    OGRSpatialReference *m_poSRSGCPCached = nullptr;
125
126
    GDALDataset *poParentDataset = nullptr;
127
128
    bool m_bOverviewsEnabled = true;
129
130
    std::vector<int>
131
        m_anBandMap{};  // used by RasterIO(). Values are 1, 2, etc.
132
133
0
    Private() = default;
134
};
135
136
struct SharedDatasetCtxt
137
{
138
    // PID of the thread that mark the dataset as shared
139
    // This may not be the actual PID, but the responsiblePID.
140
    GIntBig nPID;
141
    char *pszDescription;
142
    char *pszConcatenatedOpenOptions;
143
    int nOpenFlags;
144
145
    GDALDataset *poDS;
146
};
147
148
// Set of datasets opened as shared datasets (with GDALOpenShared)
149
// The values in the set are of type SharedDatasetCtxt.
150
static CPLHashSet *phSharedDatasetSet = nullptr;
151
152
// Set of all datasets created in the constructor of GDALDataset.
153
// In the case of a shared dataset, memorize the PID of the thread
154
// that marked the dataset as shared, so that we can remove it from
155
// the phSharedDatasetSet in the destructor of the dataset, even
156
// if GDALClose is called from a different thread.
157
static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
158
159
static CPLMutex *hDLMutex = nullptr;
160
161
// Static array of all datasets. Used by GDALGetOpenDatasets.
162
// Not thread-safe. See GDALGetOpenDatasets.
163
static GDALDataset **ppDatasets = nullptr;
164
165
static unsigned long GDALSharedDatasetHashFunc(const void *elt)
166
0
{
167
0
    const SharedDatasetCtxt *psStruct =
168
0
        static_cast<const SharedDatasetCtxt *>(elt);
169
0
    return static_cast<unsigned long>(
170
0
        CPLHashSetHashStr(psStruct->pszDescription) ^
171
0
        CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
172
0
        psStruct->nOpenFlags ^ psStruct->nPID);
173
0
}
174
175
static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
176
0
{
177
0
    const SharedDatasetCtxt *psStruct1 =
178
0
        static_cast<const SharedDatasetCtxt *>(elt1);
179
0
    const SharedDatasetCtxt *psStruct2 =
180
0
        static_cast<const SharedDatasetCtxt *>(elt2);
181
0
    return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
182
0
           strcmp(psStruct1->pszConcatenatedOpenOptions,
183
0
                  psStruct2->pszConcatenatedOpenOptions) == 0 &&
184
0
           psStruct1->nPID == psStruct2->nPID &&
185
0
           psStruct1->nOpenFlags == psStruct2->nOpenFlags;
186
0
}
187
188
static void GDALSharedDatasetFreeFunc(void *elt)
189
0
{
190
0
    SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
191
0
    CPLFree(psStruct->pszDescription);
192
0
    CPLFree(psStruct->pszConcatenatedOpenOptions);
193
0
    CPLFree(psStruct);
194
0
}
195
196
static std::string
197
GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
198
0
{
199
0
    std::string osStr;
200
0
    for (const char *pszOption : cpl::Iterate(papszOpenOptions))
201
0
        osStr += pszOption;
202
0
    return osStr;
203
0
}
204
205
/************************************************************************/
206
/*    Functions shared between gdalproxypool.cpp and gdaldataset.cpp    */
207
/************************************************************************/
208
209
// The open-shared mutex must be used by the ProxyPool too.
210
CPLMutex **GDALGetphDLMutex()
211
0
{
212
0
    return &hDLMutex;
213
0
}
214
215
// The current thread will act in the behalf of the thread of PID
216
// responsiblePID.
217
void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
218
0
{
219
0
    GIntBig *pResponsiblePID =
220
0
        static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
221
0
    if (pResponsiblePID == nullptr)
222
0
    {
223
0
        pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
224
0
        CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
225
0
    }
226
0
    *pResponsiblePID = responsiblePID;
227
0
}
228
229
// Get the PID of the thread that the current thread will act in the behalf of
230
// By default : the current thread acts in the behalf of itself.
231
GIntBig GDALGetResponsiblePIDForCurrentThread()
232
0
{
233
0
    GIntBig *pResponsiblePID =
234
0
        static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
235
0
    if (pResponsiblePID == nullptr)
236
0
        return CPLGetPID();
237
0
    return *pResponsiblePID;
238
0
}
239
240
/************************************************************************/
241
/* ==================================================================== */
242
/*                             GDALDataset                              */
243
/* ==================================================================== */
244
/************************************************************************/
245
246
/**
247
 * \class GDALDataset "gdal_priv.h"
248
 *
249
 * A dataset encapsulating one or more raster bands.  Details are further
250
 * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
251
 * Raster Data Model</a>.
252
 *
253
 * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
254
 * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
255
 * dataset.
256
 */
257
258
/************************************************************************/
259
/*                            GDALDataset()                             */
260
/************************************************************************/
261
262
//! @cond Doxygen_Suppress
263
GDALDataset::GDALDataset()
264
0
    : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
265
0
{
266
0
}
267
268
GDALDataset::GDALDataset(int bForceCachedIOIn)
269
0
    : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
270
0
      m_poPrivate(new (std::nothrow) GDALDataset::Private)
271
0
{
272
0
}
273
274
//! @endcond
275
276
/************************************************************************/
277
/*                            ~GDALDataset()                            */
278
/************************************************************************/
279
280
/**
281
 * \brief Destroy an open GDALDataset.
282
 *
283
 * This is the accepted method of closing a GDAL dataset and deallocating
284
 * all resources associated with it.
285
 *
286
 * Equivalent of the C callable GDALClose().  Except that GDALClose() first
287
 * decrements the reference count, and then closes only if it has dropped to
288
 * zero.
289
 *
290
 * For Windows users, it is not recommended to use the delete operator on the
291
 * dataset object because of known issues when allocating and freeing memory
292
 * across module boundaries. Calling GDALClose() is then a better option.
293
 */
294
295
GDALDataset::~GDALDataset()
296
297
0
{
298
    // we don't want to report destruction of datasets that
299
    // were never really open or meant as internal
300
0
    if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
301
0
    {
302
0
        if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
303
0
            CPLDebug("GDAL",
304
0
                     "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
305
0
                     GetDescription(), this, static_cast<int>(CPLGetPID()),
306
0
                     static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
307
0
        else
308
0
            CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
309
0
    }
310
311
0
    GDALDataset::Close();
312
313
    /* -------------------------------------------------------------------- */
314
    /*      Remove dataset from the "open" dataset list.                    */
315
    /* -------------------------------------------------------------------- */
316
0
    if (!bIsInternal)
317
0
    {
318
0
        CPLMutexHolderD(&hDLMutex);
319
0
        if (poAllDatasetMap)
320
0
        {
321
0
            std::map<GDALDataset *, GIntBig>::iterator oIter =
322
0
                poAllDatasetMap->find(this);
323
0
            CPLAssert(oIter != poAllDatasetMap->end());
324
325
0
            UnregisterFromSharedDataset();
326
327
0
            poAllDatasetMap->erase(oIter);
328
329
0
            if (poAllDatasetMap->empty())
330
0
            {
331
0
                delete poAllDatasetMap;
332
0
                poAllDatasetMap = nullptr;
333
0
                if (phSharedDatasetSet)
334
0
                {
335
0
                    CPLHashSetDestroy(phSharedDatasetSet);
336
0
                }
337
0
                phSharedDatasetSet = nullptr;
338
0
                CPLFree(ppDatasets);
339
0
                ppDatasets = nullptr;
340
0
            }
341
0
        }
342
0
    }
343
344
    /* -------------------------------------------------------------------- */
345
    /*      Destroy the raster bands if they exist.                         */
346
    /* -------------------------------------------------------------------- */
347
0
    for (int i = 0; i < nBands && papoBands != nullptr; ++i)
348
0
    {
349
0
        if (papoBands[i] != nullptr)
350
0
            delete papoBands[i];
351
0
        papoBands[i] = nullptr;
352
0
    }
353
354
0
    CPLFree(papoBands);
355
356
0
    if (m_poStyleTable)
357
0
    {
358
0
        delete m_poStyleTable;
359
0
        m_poStyleTable = nullptr;
360
0
    }
361
362
0
    if (m_poPrivate != nullptr)
363
0
    {
364
0
        if (m_poPrivate->hMutex != nullptr)
365
0
            CPLDestroyMutex(m_poPrivate->hMutex);
366
367
0
#if defined(__COVERITY__) || defined(DEBUG)
368
        // Not needed since at destruction there is no risk of concurrent use.
369
0
        std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
370
0
#endif
371
0
        CPLFree(m_poPrivate->m_pszWKTCached);
372
0
        if (m_poPrivate->m_poSRSCached)
373
0
        {
374
0
            m_poPrivate->m_poSRSCached->Release();
375
0
        }
376
0
        CPLFree(m_poPrivate->m_pszWKTGCPCached);
377
0
        if (m_poPrivate->m_poSRSGCPCached)
378
0
        {
379
0
            m_poPrivate->m_poSRSGCPCached->Release();
380
0
        }
381
0
    }
382
383
0
    delete m_poPrivate;
384
385
0
    CSLDestroy(papszOpenOptions);
386
0
}
387
388
/************************************************************************/
389
/*                               Close()                                */
390
/************************************************************************/
391
392
/** Do final cleanup before a dataset is destroyed.
393
 *
394
 * This method is typically called by GDALClose() or the destructor of a
395
 * GDALDataset subclass. It might also be called by C++ users before
396
 * destroying a dataset. It should not be called on a shared dataset whose
397
 * reference count is greater than one.
398
 *
399
 * It gives a last chance to the closing process to return an error code if
400
 * something goes wrong, in particular in creation / update scenarios where
401
 * file write or network communication might occur when finalizing the dataset.
402
 *
403
 * Implementations should be robust to this method to be called several times
404
 * (on subsequent calls, it should do nothing and return CE_None).
405
 * Once it has been called, no other method than Close() or the dataset
406
 * destructor should be called. RasterBand or OGRLayer owned by the dataset
407
 * should be assumed as no longer being valid.
408
 *
409
 * If a driver implements this method, it must also call it from its
410
 * dataset destructor.
411
 *
412
 * Starting with GDAL 3.13, this function may report progress if a progress
413
 * callback if provided in the pfnProgress argument and if the dataset returns
414
 * true for GDALDataset::GetCloseReportsProgress()
415
 *
416
 * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
417
 * or GDALDatasetRunCloseWithoutDestroyingEx()
418
 *
419
 * A typical implementation might look as the following
420
 * \code{.cpp}
421
 *
422
 *  MyDataset::~MyDataset()
423
 *  {
424
 *     try
425
 *     {
426
 *         MyDataset::Close();
427
 *     }
428
 *     catch (const std::exception &exc)
429
 *     {
430
 *         // If Close() can throw exception
431
 *         CPLError(CE_Failure, CPLE_AppDefined,
432
 *                  "Exception thrown in MyDataset::Close(): %s",
433
 *                  exc.what());
434
 *     }
435
 *     catch (...)
436
 *     {
437
 *         // If Close() can throw exception
438
 *         CPLError(CE_Failure, CPLE_AppDefined,
439
 *                  "Exception thrown in MyDataset::Close()");
440
 *     }
441
 *  }
442
 *
443
 *  CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
444
 *  {
445
 *      CPLErr eErr = CE_None;
446
 *      if( nOpenFlags != OPEN_FLAGS_CLOSED )
447
 *      {
448
 *          eErr = MyDataset::FlushCache(true);
449
 *
450
 *          // Do something driver specific
451
 *          if (m_fpImage)
452
 *          {
453
 *              if( VSIFCloseL(m_fpImage) != 0 )
454
 *              {
455
 *                  CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
456
 *                  eErr = CE_Failure;
457
 *              }
458
 *          }
459
 *
460
 *          // Call parent Close() implementation.
461
 *          eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
462
 *      }
463
 *      return eErr;
464
 *  }
465
 * \endcode
466
 *
467
 * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
468
 * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
469
 * @return CE_None if no error
470
 *
471
 * @since GDAL 3.7
472
 */
473
CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
474
0
{
475
0
    (void)pfnProgress;
476
0
    (void)pProgressData;
477
478
0
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
479
0
    {
480
        // Call UnregisterFromSharedDataset() before altering nOpenFlags
481
0
        UnregisterFromSharedDataset();
482
483
0
        nOpenFlags = OPEN_FLAGS_CLOSED;
484
0
    }
485
486
0
    if (IsMarkedSuppressOnClose())
487
0
    {
488
0
        if (poDriver == nullptr ||
489
            // Someone issuing Create("foo.tif") on a
490
            // memory driver doesn't expect files with those names to be deleted
491
            // on a file system...
492
            // This is somewhat messy. Ideally there should be a way for the
493
            // driver to overload the default behavior
494
0
            (!EQUAL(poDriver->GetDescription(), "MEM") &&
495
0
             !EQUAL(poDriver->GetDescription(), "Memory")))
496
0
        {
497
0
            if (VSIUnlink(GetDescription()) == 0)
498
0
                UnMarkSuppressOnClose();
499
0
        }
500
0
    }
501
502
0
    return CE_None;
503
0
}
504
505
/************************************************************************/
506
/*                GDALDatasetRunCloseWithoutDestroying()                */
507
/************************************************************************/
508
509
/** Run the Close() method, without running destruction of the object.
510
 *
511
 * This ensures that content that should be written to file is written and
512
 * that all file descriptors are closed.
513
 *
514
 * Note that this is different from GDALClose() which also destroys
515
 * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
516
 * the only functions that can be safely called on the dataset handle after
517
 * this function has been called.
518
 *
519
 * Most users want to use GDALClose() or GDALReleaseDataset() rather than
520
 * this function.
521
 *
522
 * This function is equivalent to the C++ method GDALDataset:Close()
523
 *
524
 * @param hDS dataset handle.
525
 * @return CE_None if no error
526
 *
527
 * @since GDAL 3.12
528
 * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
529
 */
530
CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
531
0
{
532
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
533
0
    return GDALDataset::FromHandle(hDS)->Close();
534
0
}
535
536
/************************************************************************/
537
/*               GDALDatasetRunCloseWithoutDestroyingEx()               */
538
/************************************************************************/
539
540
/** Run the Close() method, without running destruction of the object.
541
 *
542
 * This ensures that content that should be written to file is written and
543
 * that all file descriptors are closed.
544
 *
545
 * Note that this is different from GDALClose() which also destroys
546
 * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
547
 * the only functions that can be safely called on the dataset handle after
548
 * this function has been called.
549
 *
550
 * Most users want to use GDALClose() or GDALReleaseDataset() rather than
551
 * this function.
552
 *
553
 * This function may report progress if a progress
554
 * callback if provided in the pfnProgress argument and if the dataset returns
555
 * true for GDALDataset::GetCloseReportsProgress()
556
 *
557
 * This function is equivalent to the C++ method GDALDataset:Close()
558
 *
559
 * @param hDS dataset handle.
560
 * @param pfnProgress Progress callback, or nullptr
561
 * @param pProgressData User data of progress callback, or nullptr
562
 *
563
 * @return CE_None if no error
564
 *
565
 * @since GDAL 3.13
566
 * @see GDALClose()
567
 */
568
CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
569
                                              GDALProgressFunc pfnProgress,
570
                                              void *pProgressData)
571
0
{
572
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
573
0
    return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
574
0
}
575
576
/************************************************************************/
577
/*                      GetCloseReportsProgress()                       */
578
/************************************************************************/
579
580
/** Returns whether the Close() operation will report progress / is a potential
581
 * lengthy operation.
582
 *
583
 * At time of writing, only the COG driver will return true, if the dataset
584
 * has been created through the GDALDriver::Create() interface.
585
 *
586
 * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
587
 *
588
 * @return true if the Close() operation will report progress
589
 * @since GDAL 3.13
590
 * @see Close()
591
 */
592
bool GDALDataset::GetCloseReportsProgress() const
593
0
{
594
0
    return false;
595
0
}
596
597
/************************************************************************/
598
/*                 GDALDatasetGetCloseReportsProgress()                 */
599
/************************************************************************/
600
601
/** Returns whether the Close() operation will report progress / is a potential
602
 * lengthy operation.
603
 *
604
 * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
605
 *
606
 * @param hDS dataset handle.
607
 * @return CE_None if no error
608
 *
609
 * @return true if the Close() operation will report progress
610
 * @since GDAL 3.13
611
 * @see GDALClose()
612
 */
613
bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
614
0
{
615
0
    VALIDATE_POINTER1(hDS, __func__, false);
616
0
    return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
617
0
}
618
619
/************************************************************************/
620
/*                  CanReopenWithCurrentDescription()                   */
621
/************************************************************************/
622
623
/** Returns whether, once this dataset is closed, it can be re-opened with
624
 * Open() using the current value of GetDescription()
625
 *
626
 * The default implementation returns true. Some drivers, like MVT in Create()
627
 * mode, can return false. Some drivers return true, but the re-opened dataset
628
 * may be opened by another driver (e.g. the COG driver will return true, but
629
 * the driver used for re-opening is GTiff).
630
 *
631
 * @return true if the dataset can be re-opened using the value as
632
 *         GetDescription() as connection string for Open()
633
 * @since GDAL 3.13
634
 */
635
bool GDALDataset::CanReopenWithCurrentDescription() const
636
0
{
637
0
    return true;
638
0
}
639
640
/************************************************************************/
641
/*                    UnregisterFromSharedDataset()                     */
642
/************************************************************************/
643
644
void GDALDataset::UnregisterFromSharedDataset()
645
0
{
646
0
    if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
647
0
        return;
648
649
0
    CPLMutexHolderD(&hDLMutex);
650
651
0
    std::map<GDALDataset *, GIntBig>::iterator oIter =
652
0
        poAllDatasetMap->find(this);
653
0
    CPLAssert(oIter != poAllDatasetMap->end());
654
0
    const GIntBig nPIDCreatorForShared = oIter->second;
655
0
    bShared = false;
656
0
    SharedDatasetCtxt sStruct;
657
0
    sStruct.nPID = nPIDCreatorForShared;
658
0
    sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
659
0
    sStruct.pszDescription = const_cast<char *>(GetDescription());
660
0
    std::string osConcatenatedOpenOptions =
661
0
        GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
662
0
    sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
663
0
    sStruct.poDS = nullptr;
664
0
    SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
665
0
        CPLHashSetLookup(phSharedDatasetSet, &sStruct));
666
0
    if (psStruct && psStruct->poDS == this)
667
0
    {
668
0
        CPLHashSetRemove(phSharedDatasetSet, psStruct);
669
0
    }
670
0
    else
671
0
    {
672
0
        CPLDebug("GDAL",
673
0
                 "Should not happen. Cannot find %s, "
674
0
                 "this=%p in phSharedDatasetSet",
675
0
                 GetDescription(), this);
676
0
    }
677
0
}
678
679
/************************************************************************/
680
/*                        AddToDatasetOpenList()                        */
681
/************************************************************************/
682
683
void GDALDataset::AddToDatasetOpenList()
684
0
{
685
    /* -------------------------------------------------------------------- */
686
    /*      Add this dataset to the open dataset list.                      */
687
    /* -------------------------------------------------------------------- */
688
0
    bIsInternal = false;
689
690
0
    CPLMutexHolderD(&hDLMutex);
691
692
0
    if (poAllDatasetMap == nullptr)
693
0
        poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
694
0
    (*poAllDatasetMap)[this] = -1;
695
0
}
696
697
/************************************************************************/
698
/*                             FlushCache()                             */
699
/************************************************************************/
700
701
/**
702
 * \brief Flush all write cached data to disk.
703
 *
704
 * Any raster (or other GDAL) data written via GDAL calls, but buffered
705
 * internally will be written to disk.
706
 *
707
 * The default implementation of this method just calls the FlushCache() method
708
 * on each of the raster bands and the SyncToDisk() method
709
 * on each of the layers.  Conceptually, calling FlushCache() on a dataset
710
 * should include any work that might be accomplished by calling SyncToDisk()
711
 * on layers in that dataset.
712
 *
713
 * Using this method does not prevent use from calling GDALClose()
714
 * to properly close a dataset and ensure that important data not addressed
715
 * by FlushCache() is written in the file.
716
 *
717
 * This method is the same as the C function GDALFlushCache().
718
 *
719
 * @param bAtClosing Whether this is called from a GDALDataset destructor
720
 * @return CE_None in case of success (note: return value added in GDAL 3.7)
721
 */
722
723
CPLErr GDALDataset::FlushCache(bool bAtClosing)
724
725
0
{
726
0
    CPLErr eErr = CE_None;
727
    // This sometimes happens if a dataset is destroyed before completely
728
    // built.
729
730
0
    if (papoBands)
731
0
    {
732
0
        for (int i = 0; i < nBands; ++i)
733
0
        {
734
0
            if (papoBands[i])
735
0
            {
736
0
                if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
737
0
                    eErr = CE_Failure;
738
0
            }
739
0
        }
740
0
    }
741
742
0
    const int nLayers = GetLayerCount();
743
    // cppcheck-suppress knownConditionTrueFalse
744
0
    if (nLayers > 0)
745
0
    {
746
0
        CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
747
0
        for (int i = 0; i < nLayers; ++i)
748
0
        {
749
0
            OGRLayer *poLayer = GetLayer(i);
750
751
0
            if (poLayer)
752
0
            {
753
0
                if (poLayer->SyncToDisk() != OGRERR_NONE)
754
0
                    eErr = CE_Failure;
755
0
            }
756
0
        }
757
0
    }
758
759
0
    return eErr;
760
0
}
761
762
/************************************************************************/
763
/*                           GDALFlushCache()                           */
764
/************************************************************************/
765
766
/**
767
 * \brief Flush all write cached data to disk.
768
 *
769
 * @see GDALDataset::FlushCache().
770
 * @return CE_None in case of success (note: return value added in GDAL 3.7)
771
 */
772
773
CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
774
775
0
{
776
0
    VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
777
778
0
    return GDALDataset::FromHandle(hDS)->FlushCache(false);
779
0
}
780
781
/************************************************************************/
782
/*                             DropCache()                              */
783
/************************************************************************/
784
785
/**
786
* \brief Drop all write cached data
787
*
788
* This method is the same as the C function GDALDropCache().
789
*
790
* @return CE_None in case of success
791
* @since 3.9
792
*/
793
794
CPLErr GDALDataset::DropCache()
795
796
0
{
797
0
    CPLErr eErr = CE_None;
798
799
0
    if (papoBands)
800
0
    {
801
0
        for (int i = 0; i < nBands; ++i)
802
0
        {
803
0
            if (papoBands[i])
804
0
            {
805
0
                if (papoBands[i]->DropCache() != CE_None)
806
0
                    eErr = CE_Failure;
807
0
            }
808
0
        }
809
0
    }
810
811
0
    return eErr;
812
0
}
813
814
/************************************************************************/
815
/*                           GDALDropCache()                            */
816
/************************************************************************/
817
818
/**
819
* \brief Drop all write cached data
820
*
821
* @see GDALDataset::DropCache().
822
* @return CE_None in case of success
823
* @since 3.9
824
*/
825
826
CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
827
828
0
{
829
0
    VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
830
831
0
    return GDALDataset::FromHandle(hDS)->DropCache();
832
0
}
833
834
/************************************************************************/
835
/*                        GetEstimatedRAMUsage()                        */
836
/************************************************************************/
837
838
/**
839
 * \brief Return the intrinsic RAM usage of this dataset.
840
 *
841
 * The returned value should take into account caches in the underlying driver
842
 * and decoding library, but not the usage related to the GDAL block cache.
843
 *
844
 * At time of writing, this method is only implemented in the JP2OpenJPEG
845
 * driver. For single-tiled JPEG2000 images, the decoding of the image,
846
 * even partially, involves allocating at least
847
 * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
848
 * library.
849
 *
850
 * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
851
 * driver, to determine how long a dataset in the pool must be kept open, given
852
 * the RAM usage of the dataset with respect to the usable total RAM.
853
 *
854
 * @since GDAL 3.7
855
 * @return RAM usage in bytes, or -1 if unknown (the default implementation
856
 * returns -1)
857
 */
858
859
GIntBig GDALDataset::GetEstimatedRAMUsage()
860
0
{
861
0
    return -1;
862
0
}
863
864
/************************************************************************/
865
/*                        BlockBasedFlushCache()                        */
866
/*                                                                      */
867
/*      This helper method can be called by the                         */
868
/*      GDALDataset::FlushCache() for particular drivers to ensure      */
869
/*      that buffers will be flushed in a manner suitable for pixel     */
870
/*      interleaved (by block) IO.  That is, if all the bands have      */
871
/*      the same size blocks then a given block will be flushed for     */
872
/*      all bands before proceeding to the next block.                  */
873
/************************************************************************/
874
875
//! @cond Doxygen_Suppress
876
CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
877
878
0
{
879
0
    GDALRasterBand *poBand1 = GetRasterBand(1);
880
0
    if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
881
0
    {
882
0
        return GDALDataset::FlushCache(bAtClosing);
883
0
    }
884
885
0
    int nBlockXSize = 0;
886
0
    int nBlockYSize = 0;
887
0
    poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
888
889
    /* -------------------------------------------------------------------- */
890
    /*      Verify that all bands match.                                    */
891
    /* -------------------------------------------------------------------- */
892
0
    for (int iBand = 1; iBand < nBands; ++iBand)
893
0
    {
894
0
        GDALRasterBand *poBand = GetRasterBand(iBand + 1);
895
896
0
        int nThisBlockXSize, nThisBlockYSize;
897
0
        poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
898
0
        if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
899
0
        {
900
0
            return GDALDataset::FlushCache(bAtClosing);
901
0
        }
902
0
    }
903
904
    /* -------------------------------------------------------------------- */
905
    /*      Now flush writable data.                                        */
906
    /* -------------------------------------------------------------------- */
907
0
    for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
908
0
    {
909
0
        for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
910
0
        {
911
0
            for (int iBand = 0; iBand < nBands; ++iBand)
912
0
            {
913
0
                const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
914
915
0
                if (eErr != CE_None)
916
0
                    return CE_Failure;
917
0
            }
918
0
        }
919
0
    }
920
0
    return CE_None;
921
0
}
922
923
/************************************************************************/
924
/*                          RasterInitialize()                          */
925
/*                                                                      */
926
/*      Initialize raster size                                          */
927
/************************************************************************/
928
929
void GDALDataset::RasterInitialize(int nXSize, int nYSize)
930
931
0
{
932
0
    CPLAssert(nXSize > 0 && nYSize > 0);
933
934
0
    nRasterXSize = nXSize;
935
0
    nRasterYSize = nYSize;
936
0
}
937
938
//! @endcond
939
940
/************************************************************************/
941
/*                              AddBand()                               */
942
/************************************************************************/
943
944
/**
945
 * \fn GDALDataset::AddBand(GDALDataType, char**)
946
 * \brief Add a band to a dataset.
947
 *
948
 * This method will add a new band to the dataset if the underlying format
949
 * supports this action.  Most formats do not.
950
 *
951
 * Note that the new GDALRasterBand is not returned.  It may be fetched
952
 * after successful completion of the method by calling
953
 * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
954
 * band will always be the last band.
955
 *
956
 * @param eType the data type of the pixels in the new band.
957
 *
958
 * @param papszOptions a list of NAME=VALUE option strings.  The supported
959
 * options are format specific.  NULL may be passed by default.
960
 *
961
 * @return CE_None on success or CE_Failure on failure.
962
 */
963
964
CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
965
                            CPL_UNUSED CSLConstList papszOptions)
966
967
0
{
968
0
    ReportError(CE_Failure, CPLE_NotSupported,
969
0
                "Dataset does not support the AddBand() method.");
970
971
0
    return CE_Failure;
972
0
}
973
974
/************************************************************************/
975
/*                            GDALAddBand()                             */
976
/************************************************************************/
977
978
/**
979
 * \brief Add a band to a dataset.
980
 *
981
 * @see GDALDataset::AddBand().
982
 */
983
984
CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
985
                               CSLConstList papszOptions)
986
987
0
{
988
0
    VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
989
990
0
    return GDALDataset::FromHandle(hDataset)->AddBand(
991
0
        eType, const_cast<char **>(papszOptions));
992
0
}
993
994
/************************************************************************/
995
/*                              SetBand()                               */
996
/************************************************************************/
997
998
//! @cond Doxygen_Suppress
999
/**  Set a band in the band array, updating the band count, and array size
1000
 * appropriately.
1001
 *
1002
 * @param nNewBand new band number (indexing starts at 1)
1003
 * @param poBand band object.
1004
 */
1005
1006
void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1007
1008
0
{
1009
    /* -------------------------------------------------------------------- */
1010
    /*      Do we need to grow the bands list?                              */
1011
    /* -------------------------------------------------------------------- */
1012
0
    if (nBands < nNewBand || papoBands == nullptr)
1013
0
    {
1014
0
        GDALRasterBand **papoNewBands = nullptr;
1015
1016
0
        if (papoBands == nullptr)
1017
0
            papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1018
0
                sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1019
0
        else
1020
0
            papoNewBands = static_cast<GDALRasterBand **>(
1021
0
                VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1022
0
                                          std::max(nNewBand, nBands)));
1023
0
        if (papoNewBands == nullptr)
1024
0
        {
1025
0
            ReportError(CE_Failure, CPLE_OutOfMemory,
1026
0
                        "Cannot allocate band array");
1027
0
            return;
1028
0
        }
1029
1030
0
        papoBands = papoNewBands;
1031
1032
0
        for (int i = nBands; i < nNewBand; ++i)
1033
0
            papoBands[i] = nullptr;
1034
1035
0
        nBands = std::max(nBands, nNewBand);
1036
1037
0
        if (m_poPrivate)
1038
0
        {
1039
0
            for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1040
0
                 i < nBands; ++i)
1041
0
            {
1042
0
                m_poPrivate->m_anBandMap.push_back(i + 1);
1043
0
            }
1044
0
        }
1045
0
    }
1046
1047
    /* -------------------------------------------------------------------- */
1048
    /*      Set the band.  Resetting the band is currently not permitted.   */
1049
    /* -------------------------------------------------------------------- */
1050
0
    if (papoBands[nNewBand - 1] != nullptr)
1051
0
    {
1052
0
        ReportError(CE_Failure, CPLE_NotSupported,
1053
0
                    "Cannot set band %d as it is already set", nNewBand);
1054
0
        return;
1055
0
    }
1056
1057
0
    papoBands[nNewBand - 1] = poBand;
1058
1059
    /* -------------------------------------------------------------------- */
1060
    /*      Set back reference information on the raster band.  Note        */
1061
    /*      that the GDALDataset is a friend of the GDALRasterBand          */
1062
    /*      specifically to allow this.                                     */
1063
    /* -------------------------------------------------------------------- */
1064
0
    poBand->nBand = nNewBand;
1065
0
    poBand->poDS = this;
1066
0
    poBand->nRasterXSize = nRasterXSize;
1067
0
    poBand->nRasterYSize = nRasterYSize;
1068
0
    poBand->eAccess = eAccess;  // Default access to be same as dataset.
1069
0
}
1070
1071
//! @endcond
1072
1073
/************************************************************************/
1074
/*                              SetBand()                               */
1075
/************************************************************************/
1076
1077
//! @cond Doxygen_Suppress
1078
/**  Set a band in the band array, updating the band count, and array size
1079
 * appropriately.
1080
 *
1081
 * @param nNewBand new band number (indexing starts at 1)
1082
 * @param poBand band object.
1083
 */
1084
1085
void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1086
0
{
1087
0
    SetBand(nNewBand, poBand.release());
1088
0
}
1089
1090
//! @endcond
1091
1092
/************************************************************************/
1093
/*                           GetRasterXSize()                           */
1094
/************************************************************************/
1095
1096
/**
1097
1098
 \brief Fetch raster width in pixels.
1099
1100
 Equivalent of the C function GDALGetRasterXSize().
1101
1102
 @return the width in pixels of raster bands in this GDALDataset.
1103
1104
*/
1105
1106
int GDALDataset::GetRasterXSize() const
1107
0
{
1108
0
    return nRasterXSize;
1109
0
}
1110
1111
/************************************************************************/
1112
/*                         GDALGetRasterXSize()                         */
1113
/************************************************************************/
1114
1115
/**
1116
 * \brief Fetch raster width in pixels.
1117
 *
1118
 * @see GDALDataset::GetRasterXSize().
1119
 */
1120
1121
int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1122
1123
0
{
1124
0
    VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1125
1126
0
    return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
1127
0
}
1128
1129
/************************************************************************/
1130
/*                           GetRasterYSize()                           */
1131
/************************************************************************/
1132
1133
/**
1134
1135
 \brief Fetch raster height in pixels.
1136
1137
 Equivalent of the C function GDALGetRasterYSize().
1138
1139
 @return the height in pixels of raster bands in this GDALDataset.
1140
1141
*/
1142
1143
int GDALDataset::GetRasterYSize() const
1144
0
{
1145
0
    return nRasterYSize;
1146
0
}
1147
1148
/************************************************************************/
1149
/*                         GDALGetRasterYSize()                         */
1150
/************************************************************************/
1151
1152
/**
1153
 * \brief Fetch raster height in pixels.
1154
 *
1155
 * @see GDALDataset::GetRasterYSize().
1156
 */
1157
1158
int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1159
1160
0
{
1161
0
    VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1162
1163
0
    return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
1164
0
}
1165
1166
/************************************************************************/
1167
/*                           GetRasterBand()                            */
1168
/************************************************************************/
1169
1170
/**
1171
1172
 \brief Fetch a band object for a dataset.
1173
1174
 See GetBands() for a C++ iterator version of this method.
1175
1176
 Equivalent of the C function GDALGetRasterBand().
1177
1178
 @param nBandId the index number of the band to fetch, from 1 to
1179
                GetRasterCount().
1180
1181
 @return the nBandId th band object
1182
1183
*/
1184
1185
GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1186
1187
0
{
1188
0
    if (papoBands)
1189
0
    {
1190
0
        if (nBandId < 1 || nBandId > nBands)
1191
0
        {
1192
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1193
0
                        "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1194
0
                        nBandId);
1195
0
            return nullptr;
1196
0
        }
1197
1198
0
        return papoBands[nBandId - 1];
1199
0
    }
1200
0
    return nullptr;
1201
0
}
1202
1203
/************************************************************************/
1204
/*                           GetRasterBand()                            */
1205
/************************************************************************/
1206
1207
/**
1208
1209
 \brief Fetch a band object for a dataset.
1210
1211
 See GetBands() for a C++ iterator version of this method.
1212
1213
 Equivalent of the C function GDALGetRasterBand().
1214
1215
 @param nBandId the index number of the band to fetch, from 1 to
1216
                GetRasterCount().
1217
1218
 @return the nBandId th band object
1219
1220
*/
1221
1222
const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1223
1224
0
{
1225
0
    if (papoBands)
1226
0
    {
1227
0
        if (nBandId < 1 || nBandId > nBands)
1228
0
        {
1229
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1230
0
                        "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1231
0
                        nBandId);
1232
0
            return nullptr;
1233
0
        }
1234
1235
0
        return papoBands[nBandId - 1];
1236
0
    }
1237
0
    return nullptr;
1238
0
}
1239
1240
/************************************************************************/
1241
/*                         GDALGetRasterBand()                          */
1242
/************************************************************************/
1243
1244
/**
1245
 * \brief Fetch a band object for a dataset.
1246
 * @see GDALDataset::GetRasterBand().
1247
 */
1248
1249
GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1250
1251
0
{
1252
0
    VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1253
1254
0
    return GDALRasterBand::ToHandle(
1255
0
        GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
1256
0
}
1257
1258
/************************************************************************/
1259
/*                           GetRasterCount()                           */
1260
/************************************************************************/
1261
1262
/**
1263
 * \brief Fetch the number of raster bands on this dataset.
1264
 *
1265
 * Same as the C function GDALGetRasterCount().
1266
 *
1267
 * @return the number of raster bands.
1268
 */
1269
1270
int GDALDataset::GetRasterCount() const
1271
0
{
1272
0
    return papoBands ? nBands : 0;
1273
0
}
1274
1275
/************************************************************************/
1276
/*                         GDALGetRasterCount()                         */
1277
/************************************************************************/
1278
1279
/**
1280
 * \brief Fetch the number of raster bands on this dataset.
1281
 *
1282
 * @see GDALDataset::GetRasterCount().
1283
 */
1284
1285
int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1286
1287
0
{
1288
0
    VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1289
1290
0
    return GDALDataset::FromHandle(hDS)->GetRasterCount();
1291
0
}
1292
1293
/************************************************************************/
1294
/*                          GetProjectionRef()                          */
1295
/************************************************************************/
1296
1297
/**
1298
 * \brief Fetch the projection definition string for this dataset.
1299
 *
1300
 * Same as the C function GDALGetProjectionRef().
1301
 *
1302
 * The returned string defines the projection coordinate system of the
1303
 * image in OpenGIS WKT format.  It should be suitable for use with the
1304
 * OGRSpatialReference class.
1305
 *
1306
 * When a projection definition is not available an empty (but not NULL)
1307
 * string is returned.
1308
 *
1309
 * \note Starting with GDAL 3.0, this is a compatibility layer around
1310
 * GetSpatialRef()
1311
 *
1312
 * @return a pointer to an internal projection reference string.  It should
1313
 * not be altered, freed or expected to last for long.
1314
 *
1315
 * @see https://gdal.org/tutorials/osr_api_tut.html
1316
 */
1317
1318
const char *GDALDataset::GetProjectionRef() const
1319
0
{
1320
0
    const auto poSRS = GetSpatialRef();
1321
0
    if (!poSRS || !m_poPrivate)
1322
0
    {
1323
0
        return "";
1324
0
    }
1325
0
    char *pszWKT = nullptr;
1326
0
    poSRS->exportToWkt(&pszWKT);
1327
0
    if (!pszWKT)
1328
0
    {
1329
0
        return "";
1330
0
    }
1331
1332
    // If called on a thread-safe dataset, we might be called by several
1333
    // threads, so make sure our accesses to m_pszWKTCached are protected
1334
    // by a mutex.
1335
0
    std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1336
0
    if (m_poPrivate->m_pszWKTCached &&
1337
0
        strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1338
0
    {
1339
0
        CPLFree(pszWKT);
1340
0
        return m_poPrivate->m_pszWKTCached;
1341
0
    }
1342
0
    CPLFree(m_poPrivate->m_pszWKTCached);
1343
0
    m_poPrivate->m_pszWKTCached = pszWKT;
1344
0
    return m_poPrivate->m_pszWKTCached;
1345
0
}
1346
1347
/************************************************************************/
1348
/*                           GetSpatialRef()                            */
1349
/************************************************************************/
1350
1351
static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1352
1353
/**
1354
 * \brief Fetch the spatial reference for this dataset.
1355
 *
1356
 * Same as the C function GDALGetSpatialRef().
1357
 *
1358
 * When a projection definition is not available, null is returned. If used on
1359
 * a dataset where there are GCPs and not a geotransform, this method returns
1360
 * null. Use GetGCPSpatialRef() instead.
1361
 *
1362
 * Since GDAL 3.12, the default implementation of this method will iterate over
1363
 * vector layers and return their SRS if all geometry columns of all layers use
1364
 * the same SRS, or nullptr otherwise.
1365
 *
1366
 * @since GDAL 3.0
1367
 *
1368
 * @return a pointer to an internal object. It should not be altered or freed.
1369
 * Its lifetime will be the one of the dataset object.
1370
 *
1371
 * @see https://gdal.org/tutorials/osr_api_tut.html
1372
 */
1373
1374
const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1375
0
{
1376
0
    if (tlsEnableLayersInGetSpatialRefCounter == 0)
1377
0
        return GetSpatialRefVectorOnly();
1378
0
    return nullptr;
1379
0
}
1380
1381
/************************************************************************/
1382
/*                      GetSpatialRefVectorOnly()                       */
1383
/************************************************************************/
1384
1385
/**
1386
 * \brief Fetch the spatial reference for this dataset (only for vector layers)
1387
 *
1388
 * The default implementation of this method will iterate over
1389
 * vector layers and return their SRS if all geometry columns of all layers use
1390
 * the same SRS, or nullptr otherwise.
1391
 *
1392
 * @since GDAL 3.12
1393
 *
1394
 * @return a pointer to an internal object. It should not be altered or freed.
1395
 * Its lifetime will be the one of the dataset object.
1396
 */
1397
1398
const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1399
0
{
1400
0
    bool bInit = false;
1401
0
    const OGRSpatialReference *poGlobalSRS = nullptr;
1402
0
    for (const OGRLayer *poLayer : GetLayers())
1403
0
    {
1404
0
        for (const auto *poGeomFieldDefn :
1405
0
             poLayer->GetLayerDefn()->GetGeomFields())
1406
0
        {
1407
0
            const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1408
0
            if (!bInit)
1409
0
            {
1410
0
                bInit = true;
1411
0
                poGlobalSRS = poSRS;
1412
0
            }
1413
0
            else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1414
0
                     (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1415
0
            {
1416
0
                CPLDebug("GDAL",
1417
0
                         "Not all geometry fields or layers have the same CRS");
1418
0
                return nullptr;
1419
0
            }
1420
0
        }
1421
0
    }
1422
0
    return poGlobalSRS;
1423
0
}
1424
1425
/************************************************************************/
1426
/*                      GetSpatialRefRasterOnly()                       */
1427
/************************************************************************/
1428
1429
/**
1430
 * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
1431
 *
1432
 * @since GDAL 3.12
1433
 *
1434
 * @return a pointer to an internal object. It should not be altered or freed.
1435
 * Its lifetime will be the one of the dataset object.
1436
 */
1437
1438
const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1439
0
{
1440
0
    ++tlsEnableLayersInGetSpatialRefCounter;
1441
0
    const auto poRet = GetSpatialRef();
1442
0
    --tlsEnableLayersInGetSpatialRefCounter;
1443
0
    return poRet;
1444
0
}
1445
1446
/************************************************************************/
1447
/*                         GDALGetSpatialRef()                          */
1448
/************************************************************************/
1449
1450
/**
1451
 * \brief Fetch the spatial reference for this dataset.
1452
 *
1453
 * Same as the C++ method GDALDataset::GetSpatialRef()
1454
 *
1455
 * @since GDAL 3.0
1456
 *
1457
 * @see GDALDataset::GetSpatialRef()
1458
 */
1459
1460
OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1461
1462
0
{
1463
0
    VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1464
1465
0
    return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1466
0
        GDALDataset::FromHandle(hDS)->GetSpatialRef()));
1467
0
}
1468
1469
/************************************************************************/
1470
/*                        GDALGetProjectionRef()                        */
1471
/************************************************************************/
1472
1473
/**
1474
 * \brief Fetch the projection definition string for this dataset.
1475
 *
1476
 * @see GDALDataset::GetProjectionRef()
1477
 */
1478
1479
const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1480
1481
0
{
1482
0
    VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1483
1484
0
    return GDALDataset::FromHandle(hDS)->GetProjectionRef();
1485
0
}
1486
1487
/************************************************************************/
1488
/*                           SetProjection()                            */
1489
/************************************************************************/
1490
1491
/**
1492
 * \brief Set the projection reference string for this dataset.
1493
 *
1494
 * The string should be in OGC WKT or PROJ.4 format.  An error may occur
1495
 * because of incorrectly specified projection strings, because the dataset
1496
 * is not writable, or because the dataset does not support the indicated
1497
 * projection.  Many formats do not support writing projections.
1498
 *
1499
 * This method is the same as the C GDALSetProjection() function.
1500
 *
1501
 * \note Startig with GDAL 3.0, this is a compatibility layer around
1502
 * SetSpatialRef()
1503
1504
 * @param pszProjection projection reference string.
1505
 *
1506
 * @return CE_Failure if an error occurs, otherwise CE_None.
1507
 */
1508
1509
CPLErr GDALDataset::SetProjection(const char *pszProjection)
1510
0
{
1511
0
    if (pszProjection && pszProjection[0] != '\0')
1512
0
    {
1513
0
        OGRSpatialReference oSRS;
1514
0
        oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1515
0
        if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1516
0
        {
1517
0
            return CE_Failure;
1518
0
        }
1519
0
        return SetSpatialRef(&oSRS);
1520
0
    }
1521
0
    else
1522
0
    {
1523
0
        return SetSpatialRef(nullptr);
1524
0
    }
1525
0
}
1526
1527
/************************************************************************/
1528
/*                           SetSpatialRef()                            */
1529
/************************************************************************/
1530
1531
/**
1532
 * \brief Set the spatial reference system for this dataset.
1533
 *
1534
 * An error may occur because the dataset
1535
 * is not writable, or because the dataset does not support the indicated
1536
 * projection. Many formats do not support writing projections.
1537
 *
1538
 * This method is the same as the C GDALSetSpatialRef() function.
1539
 *
1540
 * @since GDAL 3.0
1541
1542
 * @param poSRS spatial reference system object. nullptr can potentially be
1543
 * passed for drivers that support unsetting the SRS.
1544
 *
1545
 * @return CE_Failure if an error occurs, otherwise CE_None.
1546
 */
1547
1548
CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1549
0
{
1550
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1551
0
        ReportError(CE_Failure, CPLE_NotSupported,
1552
0
                    "Dataset does not support the SetSpatialRef() method.");
1553
0
    return CE_Failure;
1554
0
}
1555
1556
/************************************************************************/
1557
/*                         GDALSetSpatialRef()                          */
1558
/************************************************************************/
1559
1560
/**
1561
 * \brief Set the spatial reference system for this dataset.
1562
 *
1563
 * @since GDAL 3.0
1564
 *
1565
 * @see GDALDataset::SetSpatialRef()
1566
 */
1567
1568
CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1569
1570
0
{
1571
0
    VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1572
1573
0
    return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1574
0
        OGRSpatialReference::FromHandle(hSRS));
1575
0
}
1576
1577
/************************************************************************/
1578
/*                         GDALSetProjection()                          */
1579
/************************************************************************/
1580
1581
/**
1582
 * \brief Set the projection reference string for this dataset.
1583
 *
1584
 * @see GDALDataset::SetProjection()
1585
 */
1586
1587
CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1588
                                     const char *pszProjection)
1589
1590
0
{
1591
0
    VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1592
1593
0
    return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
1594
0
}
1595
1596
/************************************************************************/
1597
/*                          GetGeoTransform()                           */
1598
/************************************************************************/
1599
1600
/**
1601
 * \brief Fetch the affine transformation coefficients.
1602
 *
1603
 * Fetches the coefficients for transforming between pixel/line (P,L) raster
1604
 * space, and projection coordinates (Xp,Yp) space.
1605
 *
1606
 * \code
1607
 *   Xp = gt.xorig + P*gt.xscale + L*gt.xrot;
1608
 *   Yp = gt.yorig + P*padfTransform[4] + L*gt.yscale;
1609
 * \endcode
1610
 *
1611
 * In a north up image, gt.xscale is the pixel width, and
1612
 * gt.yscale is the pixel height.  The upper left corner of the
1613
 * upper left pixel is at position (gt.xorig,gt.yorig).
1614
 *
1615
 * The default transform is (0,1,0,0,0,1) and should be returned even when
1616
 * a CE_Failure error is returned, such as for formats that don't support
1617
 * transformation to projection coordinates.
1618
 *
1619
 * This method does the same thing as the C GDALGetGeoTransform() function.
1620
 *
1621
 * @param gt an existing six double buffer into which the
1622
 * transformation will be placed.
1623
 *
1624
 * @return CE_None on success, or CE_Failure if no transform can be fetched.
1625
 *
1626
 * @since 3.12
1627
 */
1628
1629
CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform &gt) const
1630
1631
0
{
1632
0
    gt = GDALGeoTransform();
1633
1634
0
    return CE_Failure;
1635
0
}
1636
1637
/************************************************************************/
1638
/*                          GetGeoTransform()                           */
1639
/************************************************************************/
1640
1641
/**
1642
 * \brief Fetch the affine transformation coefficients.
1643
 *
1644
 * Fetches the coefficients for transforming between pixel/line (P,L) raster
1645
 * space, and projection coordinates (Xp,Yp) space.
1646
 *
1647
 * \code
1648
 *   Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
1649
 *   Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
1650
 * \endcode
1651
 *
1652
 * In a north up image, padfTransform[1] is the pixel width, and
1653
 * padfTransform[5] is the pixel height.  The upper left corner of the
1654
 * upper left pixel is at position (padfTransform[0],padfTransform[3]).
1655
 *
1656
 * The default transform is (0,1,0,0,0,1) and should be returned even when
1657
 * a CE_Failure error is returned, such as for formats that don't support
1658
 * transformation to projection coordinates.
1659
 *
1660
 * This method does the same thing as the C GDALGetGeoTransform() function.
1661
 *
1662
 * @param padfTransform an existing six double buffer into which the
1663
 * transformation will be placed.
1664
 *
1665
 * @return CE_None on success, or CE_Failure if no transform can be fetched.
1666
 *
1667
 * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
1668
 */
1669
1670
CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
1671
1672
0
{
1673
0
    return GetGeoTransform(
1674
0
        *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1675
0
}
1676
1677
/************************************************************************/
1678
/*                        GDALGetGeoTransform()                         */
1679
/************************************************************************/
1680
1681
/**
1682
 * \brief Fetch the affine transformation coefficients.
1683
 *
1684
 * @see GDALDataset::GetGeoTransform()
1685
 */
1686
1687
CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1688
1689
0
{
1690
0
    VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1691
1692
0
    return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1693
0
        *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1694
0
}
1695
1696
/************************************************************************/
1697
/*                          SetGeoTransform()                           */
1698
/************************************************************************/
1699
1700
/**
1701
 * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
1702
 * \brief Set the affine transformation coefficients.
1703
 *
1704
 * See GetGeoTransform() for details on the meaning of the padfTransform
1705
 * coefficients.
1706
 *
1707
 * This method does the same thing as the C GDALSetGeoTransform() function.
1708
 *
1709
 * @param gt the transformation coefficients to be written with the dataset.
1710
 *
1711
 * @return CE_None on success, or CE_Failure if this transform cannot be
1712
 * written.
1713
 *
1714
 * @since 3.12
1715
 */
1716
1717
CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform &gt)
1718
1719
0
{
1720
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1721
0
        ReportError(CE_Failure, CPLE_NotSupported,
1722
0
                    "SetGeoTransform() not supported for this dataset.");
1723
1724
0
    return CE_Failure;
1725
0
}
1726
1727
/************************************************************************/
1728
/*                          SetGeoTransform()                           */
1729
/************************************************************************/
1730
1731
/**
1732
 * \brief Set the affine transformation coefficients.
1733
 *
1734
 * See GetGeoTransform() for details on the meaning of the padfTransform
1735
 * coefficients.
1736
 *
1737
 * This method does the same thing as the C GDALSetGeoTransform() function.
1738
 *
1739
 * @param padfTransform a six double buffer containing the transformation
1740
 * coefficients to be written with the dataset.
1741
 *
1742
 * @return CE_None on success, or CE_Failure if this transform cannot be
1743
 * written.
1744
 *
1745
 * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
1746
 */
1747
CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
1748
1749
0
{
1750
0
    return SetGeoTransform(
1751
0
        *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1752
0
}
1753
1754
/************************************************************************/
1755
/*                        GDALSetGeoTransform()                         */
1756
/************************************************************************/
1757
1758
/**
1759
 * \brief Set the affine transformation coefficients.
1760
 *
1761
 * @see GDALDataset::SetGeoTransform()
1762
 */
1763
1764
CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1765
                                       const double *padfTransform)
1766
1767
0
{
1768
0
    VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1769
0
    VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1770
1771
0
    return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1772
0
        *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1773
0
}
1774
1775
/************************************************************************/
1776
/*                         GetInternalHandle()                          */
1777
/************************************************************************/
1778
1779
/**
1780
 * \fn GDALDataset::GetInternalHandle(const char*)
1781
 * \brief Fetch a format specific internally meaningful handle.
1782
 *
1783
 * This method is the same as the C GDALGetInternalHandle() method.
1784
 *
1785
 * @param pszHandleName the handle name desired.  The meaningful names
1786
 * will be specific to the file format.
1787
 *
1788
 * @return the desired handle value, or NULL if not recognized/supported.
1789
 */
1790
1791
void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1792
1793
0
{
1794
0
    return nullptr;
1795
0
}
1796
1797
/************************************************************************/
1798
/*                       GDALGetInternalHandle()                        */
1799
/************************************************************************/
1800
1801
/**
1802
 * \brief Fetch a format specific internally meaningful handle.
1803
 *
1804
 * @see GDALDataset::GetInternalHandle()
1805
 */
1806
1807
void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1808
                                        const char *pszRequest)
1809
1810
0
{
1811
0
    VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1812
1813
0
    return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
1814
0
}
1815
1816
/************************************************************************/
1817
/*                             GetDriver()                              */
1818
/************************************************************************/
1819
1820
/**
1821
 * \brief Fetch the driver to which this dataset relates.
1822
 *
1823
 * This method is the same as the C GDALGetDatasetDriver() function.
1824
 *
1825
 * @return the driver on which the dataset was created with GDALOpen() or
1826
 * GDALCreate().
1827
 */
1828
1829
GDALDriver *GDALDataset::GetDriver() const
1830
0
{
1831
0
    return poDriver;
1832
0
}
1833
1834
/************************************************************************/
1835
/*                        GDALGetDatasetDriver()                        */
1836
/************************************************************************/
1837
1838
/**
1839
 * \brief Fetch the driver to which this dataset relates.
1840
 *
1841
 * @see GDALDataset::GetDriver()
1842
 */
1843
1844
GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1845
1846
0
{
1847
0
    VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1848
1849
0
    return static_cast<GDALDriverH>(
1850
0
        GDALDataset::FromHandle(hDataset)->GetDriver());
1851
0
}
1852
1853
/************************************************************************/
1854
/*                             Reference()                              */
1855
/************************************************************************/
1856
1857
/**
1858
 * \brief Add one to dataset reference count.
1859
 *
1860
 * The reference is one after instantiation.
1861
 *
1862
 * This method is the same as the C GDALReferenceDataset() function.
1863
 *
1864
 * @return the post-increment reference count.
1865
 */
1866
1867
int GDALDataset::Reference()
1868
0
{
1869
0
    return ++nRefCount;
1870
0
}
1871
1872
/************************************************************************/
1873
/*                        GDALReferenceDataset()                        */
1874
/************************************************************************/
1875
1876
/**
1877
 * \brief Add one to dataset reference count.
1878
 *
1879
 * @see GDALDataset::Reference()
1880
 */
1881
1882
int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1883
1884
0
{
1885
0
    VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1886
1887
0
    return GDALDataset::FromHandle(hDataset)->Reference();
1888
0
}
1889
1890
/************************************************************************/
1891
/*                            Dereference()                             */
1892
/************************************************************************/
1893
1894
/**
1895
 * \brief Subtract one from dataset reference count.
1896
 *
1897
 * The reference is one after instantiation.  Generally when the reference
1898
 * count has dropped to zero the dataset may be safely deleted (closed).
1899
 *
1900
 * This method is the same as the C GDALDereferenceDataset() function.
1901
 *
1902
 * @return the post-decrement reference count.
1903
 */
1904
1905
int GDALDataset::Dereference()
1906
0
{
1907
0
    return --nRefCount;
1908
0
}
1909
1910
/************************************************************************/
1911
/*                       GDALDereferenceDataset()                       */
1912
/************************************************************************/
1913
1914
/**
1915
 * \brief Subtract one from dataset reference count.
1916
 *
1917
 * @see GDALDataset::Dereference()
1918
 */
1919
1920
int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1921
1922
0
{
1923
0
    VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1924
1925
0
    return GDALDataset::FromHandle(hDataset)->Dereference();
1926
0
}
1927
1928
/************************************************************************/
1929
/*                             ReleaseRef()                             */
1930
/************************************************************************/
1931
1932
/**
1933
 * \brief Drop a reference to this object, and destroy if no longer referenced.
1934
 * @return TRUE if the object has been destroyed.
1935
 */
1936
1937
int GDALDataset::ReleaseRef()
1938
1939
0
{
1940
0
    if (Dereference() <= 0)
1941
0
    {
1942
0
        nRefCount = 1;
1943
0
        delete this;
1944
0
        return TRUE;
1945
0
    }
1946
0
    return FALSE;
1947
0
}
1948
1949
/************************************************************************/
1950
/*                         GDALReleaseDataset()                         */
1951
/************************************************************************/
1952
1953
/**
1954
 * \brief Drop a reference to this object, and destroy if no longer referenced.
1955
 *
1956
 * @see GDALDataset::ReleaseRef()
1957
 */
1958
1959
int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1960
1961
0
{
1962
0
    VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1963
1964
0
    return GDALDataset::FromHandle(hDataset)->ReleaseRef();
1965
0
}
1966
1967
/************************************************************************/
1968
/*                             GetShared()                              */
1969
/************************************************************************/
1970
1971
/**
1972
 * \brief Returns shared flag.
1973
 *
1974
 * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
1975
 */
1976
1977
int GDALDataset::GetShared() const
1978
0
{
1979
0
    return bShared;
1980
0
}
1981
1982
/************************************************************************/
1983
/*                            MarkAsShared()                            */
1984
/************************************************************************/
1985
1986
/**
1987
 * \brief Mark this dataset as available for sharing.
1988
 */
1989
1990
void GDALDataset::MarkAsShared()
1991
1992
0
{
1993
0
    CPLAssert(!bShared);
1994
1995
0
    bShared = true;
1996
0
    if (bIsInternal)
1997
0
        return;
1998
1999
0
    GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
2000
2001
    // Insert the dataset in the set of shared opened datasets.
2002
0
    CPLMutexHolderD(&hDLMutex);
2003
0
    if (phSharedDatasetSet == nullptr)
2004
0
        phSharedDatasetSet =
2005
0
            CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2006
0
                          GDALSharedDatasetFreeFunc);
2007
2008
0
    SharedDatasetCtxt *psStruct =
2009
0
        static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2010
0
    psStruct->poDS = this;
2011
0
    psStruct->nPID = nPID;
2012
0
    psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2013
0
    psStruct->pszDescription = CPLStrdup(GetDescription());
2014
0
    std::string osConcatenatedOpenOptions =
2015
0
        GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2016
0
    psStruct->pszConcatenatedOpenOptions =
2017
0
        CPLStrdup(osConcatenatedOpenOptions.c_str());
2018
0
    if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
2019
0
    {
2020
0
        GDALSharedDatasetFreeFunc(psStruct);
2021
0
        ReportError(CE_Failure, CPLE_AppDefined,
2022
0
                    "An existing shared dataset already has this description. "
2023
0
                    "This should not happen.");
2024
0
    }
2025
0
    else
2026
0
    {
2027
0
        CPLHashSetInsert(phSharedDatasetSet, psStruct);
2028
2029
0
        (*poAllDatasetMap)[this] = nPID;
2030
0
    }
2031
0
}
2032
2033
/************************************************************************/
2034
/*                        MarkSuppressOnClose()                         */
2035
/************************************************************************/
2036
2037
/** Set that the dataset must be deleted on close.
2038
 *
2039
 * This is the same as C function GDALDatasetMarkSuppressOnClose()
2040
 */
2041
void GDALDataset::MarkSuppressOnClose()
2042
0
{
2043
0
    bSuppressOnClose = true;
2044
0
}
2045
2046
/************************************************************************/
2047
/*                   GDALDatasetMarkSuppressOnClose()                   */
2048
/************************************************************************/
2049
2050
/** Set that the dataset must be deleted on close.
2051
 *
2052
 * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2053
 *
2054
 * @since GDAL 3.12
2055
 */
2056
2057
void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2058
0
{
2059
0
    VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2060
2061
0
    return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2062
0
}
2063
2064
/************************************************************************/
2065
/*                       UnMarkSuppressOnClose()                        */
2066
/************************************************************************/
2067
2068
/** Remove the flag requesting the dataset to be deleted on close. */
2069
void GDALDataset::UnMarkSuppressOnClose()
2070
0
{
2071
0
    bSuppressOnClose = false;
2072
0
}
2073
2074
/************************************************************************/
2075
/*                       CleanupPostFileClosing()                       */
2076
/************************************************************************/
2077
2078
/** This method should be called by driver implementations in their destructor,
2079
 * after having closed all files, but before having freed resources that
2080
 * are needed for their GetFileList() implementation.
2081
 * This is used to implement MarkSuppressOnClose behavior.
2082
 */
2083
void GDALDataset::CleanupPostFileClosing()
2084
0
{
2085
0
    if (IsMarkedSuppressOnClose())
2086
0
    {
2087
0
        char **papszFileList = GetFileList();
2088
0
        for (int i = 0; papszFileList && papszFileList[i]; ++i)
2089
0
            VSIUnlink(papszFileList[i]);
2090
0
        CSLDestroy(papszFileList);
2091
0
    }
2092
0
}
2093
2094
/************************************************************************/
2095
/*                            GetGCPCount()                             */
2096
/************************************************************************/
2097
2098
/**
2099
 * \brief Get number of GCPs.
2100
 *
2101
 * This method is the same as the C function GDALGetGCPCount().
2102
 *
2103
 * @return number of GCPs for this dataset.  Zero if there are none.
2104
 */
2105
2106
int GDALDataset::GetGCPCount()
2107
0
{
2108
0
    return 0;
2109
0
}
2110
2111
/************************************************************************/
2112
/*                          GDALGetGCPCount()                           */
2113
/************************************************************************/
2114
2115
/**
2116
 * \brief Get number of GCPs.
2117
 *
2118
 * @see GDALDataset::GetGCPCount()
2119
 */
2120
2121
int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2122
2123
0
{
2124
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2125
2126
0
    return GDALDataset::FromHandle(hDS)->GetGCPCount();
2127
0
}
2128
2129
/************************************************************************/
2130
/*                          GetGCPProjection()                          */
2131
/************************************************************************/
2132
2133
/**
2134
 * \brief Get output projection for GCPs.
2135
 *
2136
 * This method is the same as the C function GDALGetGCPProjection().
2137
 *
2138
 * The projection string follows the normal rules from GetProjectionRef().
2139
 *
2140
 * \note Starting with GDAL 3.0, this is a compatibility layer around
2141
 * GetGCPSpatialRef()
2142
 *
2143
 * @return internal projection string or "" if there are no GCPs.
2144
 *  It should not be altered, freed or expected to last for long.
2145
 */
2146
2147
const char *GDALDataset::GetGCPProjection() const
2148
0
{
2149
0
    const auto poSRS = GetGCPSpatialRef();
2150
0
    if (!poSRS || !m_poPrivate)
2151
0
    {
2152
0
        return "";
2153
0
    }
2154
0
    char *pszWKT = nullptr;
2155
0
    poSRS->exportToWkt(&pszWKT);
2156
0
    if (!pszWKT)
2157
0
    {
2158
0
        return "";
2159
0
    }
2160
2161
    // If called on a thread-safe dataset, we might be called by several
2162
    // threads, so make sure our accesses to m_pszWKTCached are protected
2163
    // by a mutex.
2164
0
    std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2165
0
    if (m_poPrivate->m_pszWKTGCPCached &&
2166
0
        strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2167
0
    {
2168
0
        CPLFree(pszWKT);
2169
0
        return m_poPrivate->m_pszWKTGCPCached;
2170
0
    }
2171
0
    CPLFree(m_poPrivate->m_pszWKTGCPCached);
2172
0
    m_poPrivate->m_pszWKTGCPCached = pszWKT;
2173
0
    return m_poPrivate->m_pszWKTGCPCached;
2174
0
}
2175
2176
/************************************************************************/
2177
/*                          GetGCPSpatialRef()                          */
2178
/************************************************************************/
2179
2180
/**
2181
 * \brief Get output spatial reference system for GCPs.
2182
 *
2183
 * Same as the C function GDALGetGCPSpatialRef().
2184
 *
2185
 * When a SRS is not available, null is returned. If used on
2186
 * a dataset where there is a geotransform, and not GCPs, this method returns
2187
 * null. Use GetSpatialRef() instead.
2188
 *
2189
 * @since GDAL 3.0
2190
 *
2191
 * @return a pointer to an internal object. It should not be altered or freed.
2192
 * Its lifetime will be the one of the dataset object, or until the next
2193
 * call to this method.
2194
 */
2195
2196
const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2197
0
{
2198
0
    return nullptr;
2199
0
}
2200
2201
/************************************************************************/
2202
/*                        GDALGetGCPSpatialRef()                        */
2203
/************************************************************************/
2204
2205
/**
2206
 * \brief Get output spatial reference system for GCPs.
2207
 *
2208
 * @since GDAL 3.0
2209
 *
2210
 * @see GDALDataset::GetGCPSpatialRef()
2211
 */
2212
2213
OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2214
2215
0
{
2216
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2217
2218
0
    return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2219
0
        GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2220
0
}
2221
2222
/************************************************************************/
2223
/*                        GDALGetGCPProjection()                        */
2224
/************************************************************************/
2225
2226
/**
2227
 * \brief Get output projection for GCPs.
2228
 *
2229
 * @see GDALDataset::GetGCPProjection()
2230
 */
2231
2232
const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2233
2234
0
{
2235
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2236
2237
0
    return GDALDataset::FromHandle(hDS)->GetGCPProjection();
2238
0
}
2239
2240
/************************************************************************/
2241
/*                              GetGCPs()                               */
2242
/************************************************************************/
2243
2244
/**
2245
 * \brief Fetch GCPs.
2246
 *
2247
 * This method is the same as the C function GDALGetGCPs().
2248
 *
2249
 * @return pointer to internal GCP structure list.  It should not be modified,
2250
 * and may change on the next GDAL call.
2251
 */
2252
2253
const GDAL_GCP *GDALDataset::GetGCPs()
2254
0
{
2255
0
    return nullptr;
2256
0
}
2257
2258
/************************************************************************/
2259
/*                            GDALGetGCPs()                             */
2260
/************************************************************************/
2261
2262
/**
2263
 * \brief Fetch GCPs.
2264
 *
2265
 * @see GDALDataset::GetGCPs()
2266
 */
2267
2268
const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2269
2270
0
{
2271
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2272
2273
0
    return GDALDataset::FromHandle(hDS)->GetGCPs();
2274
0
}
2275
2276
/************************************************************************/
2277
/*                              SetGCPs()                               */
2278
/************************************************************************/
2279
2280
/**
2281
 * \brief Assign GCPs.
2282
 *
2283
 * This method is the same as the C function GDALSetGCPs().
2284
 *
2285
 * This method assigns the passed set of GCPs to this dataset, as well as
2286
 * setting their coordinate system.  Internally copies are made of the
2287
 * coordinate system and list of points, so the caller remains responsible for
2288
 * deallocating these arguments if appropriate.
2289
 *
2290
 * Most formats do not support setting of GCPs, even formats that can
2291
 * handle GCPs.  These formats will return CE_Failure.
2292
 *
2293
 * \note Startig with GDAL 3.0, this is a compatibility layer around
2294
 * SetGCPs(int, const GDAL_GCP*, const char*)
2295
 *
2296
 * @param nGCPCount number of GCPs being assigned.
2297
 *
2298
 * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2299
 *
2300
 * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
2301
 * GCP output coordinates.  This parameter should be "" if no output coordinate
2302
 * system is known.
2303
 *
2304
 * @return CE_None on success, CE_Failure on failure (including if action is
2305
 * not supported for this format).
2306
 */
2307
2308
CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2309
                            const char *pszGCPProjection)
2310
2311
0
{
2312
0
    if (pszGCPProjection && pszGCPProjection[0] != '\0')
2313
0
    {
2314
0
        OGRSpatialReference oSRS;
2315
0
        oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2316
0
        if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
2317
0
        {
2318
0
            return CE_Failure;
2319
0
        }
2320
0
        return SetGCPs(nGCPCount, pasGCPList, &oSRS);
2321
0
    }
2322
0
    else
2323
0
    {
2324
0
        return SetGCPs(nGCPCount, pasGCPList,
2325
0
                       static_cast<const OGRSpatialReference *>(nullptr));
2326
0
    }
2327
0
}
2328
2329
/************************************************************************/
2330
/*                              SetGCPs()                               */
2331
/************************************************************************/
2332
2333
/**
2334
 * \brief Assign GCPs.
2335
 *
2336
 * This method is the same as the C function GDALSetGCPs().
2337
 *
2338
 * This method assigns the passed set of GCPs to this dataset, as well as
2339
 * setting their coordinate system.  Internally copies are made of the
2340
 * coordinate system and list of points, so the caller remains responsible for
2341
 * deallocating these arguments if appropriate.
2342
 *
2343
 * Most formats do not support setting of GCPs, even formats that can
2344
 * handle GCPs.  These formats will return CE_Failure.
2345
 *
2346
 * @since GDAL 3.0
2347
 *
2348
 * @param nGCPCount number of GCPs being assigned.
2349
 *
2350
 * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2351
 *
2352
 * @param poGCP_SRS the new coordinate reference system to assign for the
2353
 * GCP output coordinates.  This parameter should be null if no output
2354
 * coordinate system is known.
2355
 *
2356
 * @return CE_None on success, CE_Failure on failure (including if action is
2357
 * not supported for this format).
2358
 */
2359
2360
CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
2361
                            CPL_UNUSED const GDAL_GCP *pasGCPList,
2362
                            CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
2363
2364
0
{
2365
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2366
0
        ReportError(CE_Failure, CPLE_NotSupported,
2367
0
                    "Dataset does not support the SetGCPs() method.");
2368
2369
0
    return CE_Failure;
2370
0
}
2371
2372
/************************************************************************/
2373
/*                            GDALSetGCPs()                             */
2374
/************************************************************************/
2375
2376
/**
2377
 * \brief Assign GCPs.
2378
 *
2379
 * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
2380
 */
2381
2382
CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2383
                               const GDAL_GCP *pasGCPList,
2384
                               const char *pszGCPProjection)
2385
2386
0
{
2387
0
    VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2388
2389
0
    return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2390
0
                                                 pszGCPProjection);
2391
0
}
2392
2393
/************************************************************************/
2394
/*                            GDALSetGCPs2()                            */
2395
/************************************************************************/
2396
2397
/**
2398
 * \brief Assign GCPs.
2399
 *
2400
 * @since GDAL 3.0
2401
 * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
2402
 */
2403
2404
CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
2405
                    OGRSpatialReferenceH hSRS)
2406
2407
0
{
2408
0
    VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
2409
2410
0
    return GDALDataset::FromHandle(hDS)->SetGCPs(
2411
0
        nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
2412
0
}
2413
2414
/************************************************************************/
2415
/*                           BuildOverviews()                           */
2416
/************************************************************************/
2417
2418
/**
2419
 * \brief Build raster overview(s)
2420
 *
2421
 * If the operation is not supported for the indicated dataset, then
2422
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
2423
 * CPLE_NotSupported.
2424
 *
2425
 * Depending on the actual file format, all overviews level can be also
2426
 * deleted by specifying nOverviews == 0. This works at least for external
2427
 * overviews (.ovr), TIFF internal overviews, etc.
2428
 *
2429
 * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
2430
 * to "ALL_CPUS" or a integer value to specify the number of threads to use for
2431
 * overview computation.
2432
 *
2433
 * This method is the same as the C function GDALBuildOverviewsEx().
2434
 *
2435
 * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
2436
 * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
2437
 * or "NONE" controlling the downsampling method applied.
2438
 * @param nOverviews number of overviews to build, or 0 to clean overviews.
2439
 * @param panOverviewList the list of overview decimation factors (positive
2440
 *                        integers, normally larger or equal to 2) to build, or
2441
 *                        NULL if nOverviews == 0.
2442
 * @param nListBands number of bands to build overviews for in panBandList.
2443
 * Build for all bands if this is 0.
2444
 * @param panBandList list of band numbers.
2445
 * @param pfnProgress a function to call to report progress, or NULL.
2446
 * @param pProgressData application data to pass to the progress function.
2447
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2448
 *                     key=value pairs, or NULL.
2449
 *                     Possible keys are the ones returned by
2450
 *                     GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2451
 *
2452
 * @return CE_None on success or CE_Failure if the operation doesn't work.
2453
 *
2454
 * For example, to build overview level 2, 4 and 8 on all bands the following
2455
 * call could be made:
2456
 * \code{.cpp}
2457
 *   int       anOverviewList[3] = { 2, 4, 8 };
2458
 *
2459
 *   poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
2460
 *                              GDALDummyProgress, nullptr );
2461
 * \endcode
2462
 *
2463
 * @see GDALRegenerateOverviewsEx()
2464
 */
2465
2466
CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
2467
                                   const int *panOverviewList, int nListBands,
2468
                                   const int *panBandList,
2469
                                   GDALProgressFunc pfnProgress,
2470
                                   void *pProgressData,
2471
                                   CSLConstList papszOptions)
2472
0
{
2473
0
    int *panAllBandList = nullptr;
2474
2475
0
    CPLStringList aosOptions(papszOptions);
2476
0
    if (poDriver && !aosOptions.empty())
2477
0
    {
2478
0
        const char *pszOptionList =
2479
0
            poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
2480
0
        if (pszOptionList)
2481
0
        {
2482
            // For backwards compatibility
2483
0
            if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
2484
0
            {
2485
0
                if (strstr(pszOptionList, "<Value>RRD</Value>") &&
2486
0
                    aosOptions.FetchNameValue("LOCATION") == nullptr)
2487
0
                {
2488
0
                    if (CPLTestBool(opt))
2489
0
                        aosOptions.SetNameValue("LOCATION", "RRD");
2490
0
                    aosOptions.SetNameValue("USE_RRD", nullptr);
2491
0
                }
2492
0
            }
2493
0
            if (const char *opt =
2494
0
                    aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
2495
0
            {
2496
0
                if (strstr(pszOptionList, "VIRTUAL"))
2497
0
                {
2498
0
                    aosOptions.SetNameValue("VIRTUAL", opt);
2499
0
                    aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
2500
0
                }
2501
0
            }
2502
2503
0
            for (const auto &[pszKey, pszValue] :
2504
0
                 cpl::IterateNameValue(papszOptions))
2505
0
            {
2506
0
                if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
2507
0
                {
2508
0
                    aosOptions.SetNameValue(
2509
0
                        std::string(pszKey)
2510
0
                            .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
2511
0
                            .c_str(),
2512
0
                        pszValue);
2513
0
                    aosOptions.SetNameValue(pszKey, nullptr);
2514
0
                }
2515
0
            }
2516
2517
0
            CPLString osDriver;
2518
0
            osDriver.Printf("driver %s", poDriver->GetDescription());
2519
0
            GDALValidateOptions(pszOptionList, aosOptions.List(),
2520
0
                                "overview creation option", osDriver);
2521
0
        }
2522
0
    }
2523
2524
0
    if (nListBands == 0)
2525
0
    {
2526
0
        nListBands = GetRasterCount();
2527
0
        panAllBandList =
2528
0
            static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2529
0
        for (int i = 0; i < nListBands; ++i)
2530
0
            panAllBandList[i] = i + 1;
2531
2532
0
        panBandList = panAllBandList;
2533
0
    }
2534
2535
0
    if (pfnProgress == nullptr)
2536
0
        pfnProgress = GDALDummyProgress;
2537
2538
0
    for (int i = 0; i < nOverviews; ++i)
2539
0
    {
2540
0
        if (panOverviewList[i] <= 0)
2541
0
        {
2542
0
            CPLError(CE_Failure, CPLE_IllegalArg,
2543
0
                     "panOverviewList[%d] = %d is invalid. It must be a "
2544
0
                     "positive value",
2545
0
                     i, panOverviewList[i]);
2546
0
            CPLFree(panAllBandList);
2547
0
            return CE_Failure;
2548
0
        }
2549
0
    }
2550
2551
0
    const CPLErr eErr = IBuildOverviews(
2552
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2553
0
        pfnProgress, pProgressData, aosOptions.List());
2554
2555
0
    if (panAllBandList != nullptr)
2556
0
        CPLFree(panAllBandList);
2557
2558
0
    return eErr;
2559
0
}
2560
2561
/************************************************************************/
2562
/*                         GDALBuildOverviews()                         */
2563
/************************************************************************/
2564
2565
/**
2566
 * \brief Build raster overview(s)
2567
 *
2568
 * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2569
 */
2570
2571
CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2572
                                      const char *pszResampling, int nOverviews,
2573
                                      const int *panOverviewList,
2574
                                      int nListBands, const int *panBandList,
2575
                                      GDALProgressFunc pfnProgress,
2576
                                      void *pProgressData)
2577
2578
0
{
2579
0
    VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2580
2581
0
    return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2582
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2583
0
        pfnProgress, pProgressData, nullptr);
2584
0
}
2585
2586
/************************************************************************/
2587
/*                         GDALBuildOverviews()                         */
2588
/************************************************************************/
2589
2590
/**
2591
 * \brief Build raster overview(s)
2592
 *
2593
 * @see GDALDataset::BuildOverviews()
2594
 * @since GDAL 3.6
2595
 */
2596
2597
CPLErr CPL_STDCALL
2598
GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2599
                     int nOverviews, const int *panOverviewList, int nListBands,
2600
                     const int *panBandList, GDALProgressFunc pfnProgress,
2601
                     void *pProgressData, CSLConstList papszOptions)
2602
2603
0
{
2604
0
    VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2605
2606
0
    return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2607
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2608
0
        pfnProgress, pProgressData, papszOptions);
2609
0
}
2610
2611
/************************************************************************/
2612
/*                          IBuildOverviews()                           */
2613
/*                                                                      */
2614
/*      Default implementation.                                         */
2615
/************************************************************************/
2616
2617
//! @cond Doxygen_Suppress
2618
CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2619
                                    const int *panOverviewList, int nListBands,
2620
                                    const int *panBandList,
2621
                                    GDALProgressFunc pfnProgress,
2622
                                    void *pProgressData,
2623
                                    CSLConstList papszOptions)
2624
2625
0
{
2626
0
    if (oOvManager.IsInitialized())
2627
0
        return oOvManager.BuildOverviews(
2628
0
            nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2629
0
            panBandList, pfnProgress, pProgressData, papszOptions);
2630
0
    else
2631
0
    {
2632
0
        ReportError(CE_Failure, CPLE_NotSupported,
2633
0
                    "BuildOverviews() not supported for this dataset.");
2634
2635
0
        return CE_Failure;
2636
0
    }
2637
0
}
2638
2639
//! @endcond
2640
2641
/************************************************************************/
2642
/*                            AddOverviews()                            */
2643
/*                                                                      */
2644
/*      Default implementation.                                         */
2645
/************************************************************************/
2646
2647
/**
2648
 * \brief Add overview from existing dataset(s)
2649
 *
2650
 * This function creates new overview levels or refresh existing one from
2651
 * the list of provided overview datasets.
2652
 * Source overviews may come from any GDAL supported format, provided they
2653
 * have the same number of bands and geospatial extent than the target
2654
 * dataset.
2655
 *
2656
 * If the operation is not supported for the indicated dataset, then
2657
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
2658
 * CPLE_NotSupported.
2659
 *
2660
 * At time of writing, this method is only implemented for internal overviews
2661
 * of GeoTIFF datasets and external overviews in GeoTIFF format.
2662
 *
2663
 * @param apoSrcOvrDS Vector of source overviews.
2664
 * @param pfnProgress a function to call to report progress, or NULL.
2665
 * @param pProgressData application data to pass to the progress function.
2666
 * @param papszOptions NULL terminated list of options as
2667
 *                     key=value pairs, or NULL. Possible keys are the
2668
 *                     ones returned by
2669
 *                     GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2670
 *
2671
 * @return CE_None on success or CE_Failure if the operation doesn't work.
2672
 * @since 3.12
2673
 */
2674
CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2675
                                 GDALProgressFunc pfnProgress,
2676
                                 void *pProgressData, CSLConstList papszOptions)
2677
0
{
2678
0
    if (oOvManager.IsInitialized())
2679
0
    {
2680
0
        return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2681
0
                                       pProgressData, papszOptions);
2682
0
    }
2683
0
    else
2684
0
    {
2685
0
        ReportError(CE_Failure, CPLE_NotSupported,
2686
0
                    "AddOverviews() not supported for this dataset.");
2687
0
        return CE_Failure;
2688
0
    }
2689
0
}
2690
2691
/************************************************************************/
2692
/*                             IRasterIO()                              */
2693
/*                                                                      */
2694
/*      The default implementation of IRasterIO() is, in the general    */
2695
/*      case to pass the request off to each band objects rasterio      */
2696
/*      methods with appropriate arguments. In some cases, it might     */
2697
/*      choose instead the BlockBasedRasterIO() implementation.         */
2698
/************************************************************************/
2699
2700
//! @cond Doxygen_Suppress
2701
CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2702
                              int nXSize, int nYSize, void *pData,
2703
                              int nBufXSize, int nBufYSize,
2704
                              GDALDataType eBufType, int nBandCount,
2705
                              BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2706
                              GSpacing nLineSpace, GSpacing nBandSpace,
2707
                              GDALRasterIOExtraArg *psExtraArg)
2708
2709
0
{
2710
0
    const char *pszInterleave = nullptr;
2711
2712
0
    CPLAssert(nullptr != pData);
2713
2714
0
    const bool bHasSubpixelShift =
2715
0
        psExtraArg->bFloatingPointWindowValidity &&
2716
0
        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2717
0
        (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2718
2719
0
    if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2720
0
        nBandCount > 1 &&
2721
0
        (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2722
0
            nullptr &&
2723
0
        EQUAL(pszInterleave, "PIXEL"))
2724
0
    {
2725
0
        return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2726
0
                                  nBufXSize, nBufYSize, eBufType, nBandCount,
2727
0
                                  panBandMap, nPixelSpace, nLineSpace,
2728
0
                                  nBandSpace, psExtraArg);
2729
0
    }
2730
2731
0
    if (eRWFlag == GF_Read &&
2732
0
        (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2733
0
         psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2734
0
         psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2735
0
         psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2736
0
        !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2737
0
    {
2738
0
        if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2739
0
        {
2740
0
            int bTried = FALSE;
2741
0
            const CPLErr eErr = TryOverviewRasterIO(
2742
0
                eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2743
0
                nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2744
0
                nLineSpace, nBandSpace, psExtraArg, &bTried);
2745
0
            if (bTried)
2746
0
                return eErr;
2747
0
        }
2748
2749
0
        GDALDataType eFirstBandDT = GDT_Unknown;
2750
0
        int nFirstMaskFlags = 0;
2751
0
        GDALRasterBand *poFirstMaskBand = nullptr;
2752
0
        int nOKBands = 0;
2753
2754
        // Check if bands share the same mask band
2755
0
        for (int i = 0; i < nBandCount; ++i)
2756
0
        {
2757
0
            GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2758
0
            if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2759
0
                poBand->GetOverviewCount())
2760
0
            {
2761
                // Could be improved to select the appropriate overview.
2762
0
                break;
2763
0
            }
2764
0
            if (poBand->GetColorTable() != nullptr)
2765
0
            {
2766
0
                break;
2767
0
            }
2768
0
            const GDALDataType eDT = poBand->GetRasterDataType();
2769
0
            if (GDALDataTypeIsComplex(eDT))
2770
0
            {
2771
0
                break;
2772
0
            }
2773
0
            if (i == 0)
2774
0
            {
2775
0
                eFirstBandDT = eDT;
2776
0
                nFirstMaskFlags = poBand->GetMaskFlags();
2777
0
                if (nFirstMaskFlags == GMF_NODATA)
2778
0
                {
2779
                    // The dataset-level resampling code is not ready for nodata
2780
                    // Fallback to band-level resampling
2781
0
                    break;
2782
0
                }
2783
0
                poFirstMaskBand = poBand->GetMaskBand();
2784
0
            }
2785
0
            else
2786
0
            {
2787
0
                if (eDT != eFirstBandDT)
2788
0
                {
2789
0
                    break;
2790
0
                }
2791
0
                int nMaskFlags = poBand->GetMaskFlags();
2792
0
                if (nMaskFlags == GMF_NODATA)
2793
0
                {
2794
                    // The dataset-level resampling code is not ready for nodata
2795
                    // Fallback to band-level resampling
2796
0
                    break;
2797
0
                }
2798
0
                GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2799
0
                if (nFirstMaskFlags == GMF_ALL_VALID &&
2800
0
                    nMaskFlags == GMF_ALL_VALID)
2801
0
                {
2802
                    // Ok.
2803
0
                }
2804
0
                else if (poFirstMaskBand == poMaskBand)
2805
0
                {
2806
                    // Ok.
2807
0
                }
2808
0
                else
2809
0
                {
2810
0
                    break;
2811
0
                }
2812
0
            }
2813
2814
0
            ++nOKBands;
2815
0
        }
2816
2817
0
        GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2818
0
        void *pProgressDataGlobal = psExtraArg->pProgressData;
2819
2820
0
        CPLErr eErr = CE_None;
2821
0
        if (nOKBands > 0)
2822
0
        {
2823
0
            if (nOKBands < nBandCount)
2824
0
            {
2825
0
                psExtraArg->pfnProgress = GDALScaledProgress;
2826
0
                psExtraArg->pProgressData = GDALCreateScaledProgress(
2827
0
                    0.0, static_cast<double>(nOKBands) / nBandCount,
2828
0
                    pfnProgressGlobal, pProgressDataGlobal);
2829
0
                if (psExtraArg->pProgressData == nullptr)
2830
0
                    psExtraArg->pfnProgress = nullptr;
2831
0
            }
2832
2833
0
            eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2834
0
                                     pData, nBufXSize, nBufYSize, eBufType,
2835
0
                                     nOKBands, panBandMap, nPixelSpace,
2836
0
                                     nLineSpace, nBandSpace, psExtraArg);
2837
2838
0
            if (nOKBands < nBandCount)
2839
0
            {
2840
0
                GDALDestroyScaledProgress(psExtraArg->pProgressData);
2841
0
            }
2842
0
        }
2843
0
        if (eErr == CE_None && nOKBands < nBandCount)
2844
0
        {
2845
0
            if (nOKBands > 0)
2846
0
            {
2847
0
                psExtraArg->pfnProgress = GDALScaledProgress;
2848
0
                psExtraArg->pProgressData = GDALCreateScaledProgress(
2849
0
                    static_cast<double>(nOKBands) / nBandCount, 1.0,
2850
0
                    pfnProgressGlobal, pProgressDataGlobal);
2851
0
                if (psExtraArg->pProgressData == nullptr)
2852
0
                    psExtraArg->pfnProgress = nullptr;
2853
0
            }
2854
0
            eErr = BandBasedRasterIO(
2855
0
                eRWFlag, nXOff, nYOff, nXSize, nYSize,
2856
0
                static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2857
0
                nBufYSize, eBufType, nBandCount - nOKBands,
2858
0
                panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2859
0
                psExtraArg);
2860
0
            if (nOKBands > 0)
2861
0
            {
2862
0
                GDALDestroyScaledProgress(psExtraArg->pProgressData);
2863
0
            }
2864
0
        }
2865
2866
0
        psExtraArg->pfnProgress = pfnProgressGlobal;
2867
0
        psExtraArg->pProgressData = pProgressDataGlobal;
2868
2869
0
        return eErr;
2870
0
    }
2871
2872
0
    return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2873
0
                             nBufXSize, nBufYSize, eBufType, nBandCount,
2874
0
                             panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2875
0
                             psExtraArg);
2876
0
}
2877
2878
//! @endcond
2879
2880
/************************************************************************/
2881
/*                         BandBasedRasterIO()                          */
2882
/*                                                                      */
2883
/*      Pass the request off to each band objects rasterio methods with */
2884
/*      appropriate arguments.                                          */
2885
/************************************************************************/
2886
2887
//! @cond Doxygen_Suppress
2888
CPLErr GDALDataset::BandBasedRasterIO(
2889
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2890
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2891
    int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2892
    GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2893
2894
0
{
2895
0
    int iBandIndex;
2896
0
    CPLErr eErr = CE_None;
2897
2898
0
    GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2899
0
    void *pProgressDataGlobal = psExtraArg->pProgressData;
2900
2901
0
    for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2902
0
         ++iBandIndex)
2903
0
    {
2904
0
        GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2905
2906
0
        if (poBand == nullptr)
2907
0
        {
2908
0
            eErr = CE_Failure;
2909
0
            break;
2910
0
        }
2911
2912
0
        GByte *pabyBandData =
2913
0
            static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2914
2915
0
        if (nBandCount > 1)
2916
0
        {
2917
0
            psExtraArg->pfnProgress = GDALScaledProgress;
2918
0
            psExtraArg->pProgressData = GDALCreateScaledProgress(
2919
0
                1.0 * iBandIndex / nBandCount,
2920
0
                1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2921
0
                pProgressDataGlobal);
2922
0
            if (psExtraArg->pProgressData == nullptr)
2923
0
                psExtraArg->pfnProgress = nullptr;
2924
0
        }
2925
2926
0
        eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2927
0
                                 pabyBandData, nBufXSize, nBufYSize, eBufType,
2928
0
                                 nPixelSpace, nLineSpace, psExtraArg);
2929
2930
0
        if (nBandCount > 1)
2931
0
            GDALDestroyScaledProgress(psExtraArg->pProgressData);
2932
0
    }
2933
2934
0
    psExtraArg->pfnProgress = pfnProgressGlobal;
2935
0
    psExtraArg->pProgressData = pProgressDataGlobal;
2936
2937
0
    return eErr;
2938
0
}
2939
2940
//! @endcond
2941
2942
/************************************************************************/
2943
/*               ValidateRasterIOOrAdviseReadParameters()               */
2944
/************************************************************************/
2945
2946
//! @cond Doxygen_Suppress
2947
CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2948
    const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2949
    int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2950
    int nBandCount, const int *panBandMap)
2951
0
{
2952
0
    if (nBands == 0)
2953
0
    {
2954
0
        *pbStopProcessingOnCENone = TRUE;
2955
0
        return CE_None;
2956
0
    }
2957
2958
    /* -------------------------------------------------------------------- */
2959
    /*      Some size values are "noop".  Lets just return to avoid         */
2960
    /*      stressing lower level functions.                                */
2961
    /* -------------------------------------------------------------------- */
2962
0
    if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2963
0
    {
2964
0
        CPLDebug("GDAL",
2965
0
                 "%s skipped for odd window or buffer size.\n"
2966
0
                 "  Window = (%d,%d)x%dx%d\n"
2967
0
                 "  Buffer = %dx%d",
2968
0
                 pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2969
0
                 nBufYSize);
2970
2971
0
        *pbStopProcessingOnCENone = TRUE;
2972
0
        return CE_None;
2973
0
    }
2974
2975
0
    CPLErr eErr = CE_None;
2976
0
    *pbStopProcessingOnCENone = FALSE;
2977
2978
0
    if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2979
0
        nYSize > nRasterYSize - nYOff)
2980
0
    {
2981
0
        ReportError(CE_Failure, CPLE_IllegalArg,
2982
0
                    "Access window out of range in %s.  Requested "
2983
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
2984
0
                    pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2985
0
                    nRasterYSize);
2986
0
        eErr = CE_Failure;
2987
0
    }
2988
2989
0
    if (panBandMap == nullptr && nBandCount > GetRasterCount())
2990
0
    {
2991
0
        ReportError(CE_Failure, CPLE_IllegalArg,
2992
0
                    "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2993
0
                    GetRasterCount());
2994
0
        eErr = CE_Failure;
2995
0
    }
2996
2997
0
    for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2998
0
    {
2999
0
        int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
3000
0
        if (iBand < 1 || iBand > GetRasterCount())
3001
0
        {
3002
0
            ReportError(
3003
0
                CE_Failure, CPLE_IllegalArg,
3004
0
                "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
3005
0
                pszCallingFunc, i, iBand);
3006
0
            eErr = CE_Failure;
3007
0
        }
3008
3009
0
        if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3010
0
        {
3011
0
            ReportError(
3012
0
                CE_Failure, CPLE_IllegalArg,
3013
0
                "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3014
0
                pszCallingFunc, i, iBand);
3015
0
            eErr = CE_Failure;
3016
0
        }
3017
0
    }
3018
3019
0
    return eErr;
3020
0
}
3021
3022
//! @endcond
3023
3024
/************************************************************************/
3025
/*                              RasterIO()                              */
3026
/************************************************************************/
3027
3028
/**
3029
 * \brief Read/write a region of image data from multiple bands.
3030
 *
3031
 * This method allows reading a region of one or more GDALRasterBands from
3032
 * this dataset into a buffer,  or writing data from a buffer into a region
3033
 * of the GDALRasterBands.  It automatically takes care of data type
3034
 * translation if the data type (eBufType) of the buffer is different than
3035
 * that of the GDALRasterBand.
3036
 * The method also takes care of image decimation / replication if the
3037
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
3038
 * region being accessed (nXSize x nYSize).
3039
 *
3040
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3041
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3042
 * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3043
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
3044
 * Or use nLineSpace and a possibly shifted pData value.
3045
 *
3046
 * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3047
 * writing from various organization of buffers.
3048
 *
3049
 * Some formats may efficiently implement decimation into a buffer by
3050
 * reading from lower resolution overview images. The logic of the default
3051
 * implementation in the base class GDALRasterBand is the following one. It
3052
 * computes a target_downscaling_factor from the window of interest and buffer
3053
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3054
 * It then walks through overviews and will select the first one whose
3055
 * downscaling factor is greater than target_downscaling_factor / 1.2.
3056
 *
3057
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3058
 * The relationship between target_downscaling_factor and the select overview
3059
 * level is the following one:
3060
 *
3061
 * target_downscaling_factor  | selected_overview
3062
 * -------------------------  | -----------------
3063
 * ]0,       2 / 1.2]         | full resolution band
3064
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
3065
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
3066
 * ]8 / 1.2, infinity[        | 8x downsampled band
3067
 *
3068
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3069
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3070
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3071
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3072
 * this oversampling threshold defaults to 1. Consequently if there are overviews
3073
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3074
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3075
 *
3076
 * For highest performance full resolution data access, read and write
3077
 * on "block boundaries" as returned by GetBlockSize(), or use the
3078
 * ReadBlock() and WriteBlock() methods.
3079
 *
3080
 * This method is the same as the C GDALDatasetRasterIO() or
3081
 * GDALDatasetRasterIOEx() functions.
3082
 *
3083
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3084
 * write a region of data.
3085
 *
3086
 * @param nXOff The pixel offset to the top left corner of the region
3087
 * of the band to be accessed.  This would be zero to start from the left side.
3088
 *
3089
 * @param nYOff The line offset to the top left corner of the region
3090
 * of the band to be accessed.  This would be zero to start from the top.
3091
 *
3092
 * @param nXSize The width of the region of the band to be accessed in pixels.
3093
 *
3094
 * @param nYSize The height of the region of the band to be accessed in lines.
3095
 *
3096
 * @param pData The buffer into which the data should be read, or from which
3097
 * it should be written.  This buffer must contain at least
3098
 * nBufXSize * nBufYSize * nBandCount words of type eBufType.  It is organized
3099
 * in left to right,top to bottom pixel order.  Spacing is controlled by the
3100
 * nPixelSpace, and nLineSpace parameters.
3101
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3102
 * temporarily modified during the execution of this method (and eventually
3103
 * restored back to its original content), so it is not safe to use a buffer
3104
 * stored in a read-only section of the calling program.
3105
 *
3106
 * @param nBufXSize the width of the buffer image into which the desired region
3107
 * is to be read, or from which it is to be written.
3108
 *
3109
 * @param nBufYSize the height of the buffer image into which the desired
3110
 * region is to be read, or from which it is to be written.
3111
 *
3112
 * @param eBufType the type of the pixel values in the pData data buffer. The
3113
 * pixel values will automatically be translated to/from the GDALRasterBand
3114
 * data type as needed. Most driver implementations will use GDALCopyWords64()
3115
 * to perform data type translation.
3116
 *
3117
 * @param nBandCount the number of bands being read or written.
3118
 *
3119
 * @param panBandMap the list of nBandCount band numbers being read/written.
3120
 * Note band numbers are 1 based. This may be NULL to select the first
3121
 * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3122
 * not "const int*")
3123
 *
3124
 * @param nPixelSpace The byte offset from the start of one pixel value in
3125
 * pData to the start of the next pixel value within a scanline. If defaulted
3126
 * (0) the size of the datatype eBufType is used.
3127
 *
3128
 * @param nLineSpace The byte offset from the start of one scanline in
3129
 * pData to the start of the next. If defaulted (0) the size of the datatype
3130
 * eBufType * nBufXSize is used.
3131
 *
3132
 * @param nBandSpace the byte offset from the start of one bands data to the
3133
 * start of the next. If defaulted (0) the value will be
3134
 * nLineSpace * nBufYSize implying band sequential organization
3135
 * of the data buffer.
3136
 *
3137
 * @param psExtraArg pointer to a GDALRasterIOExtraArg
3138
 * structure with additional arguments to specify resampling and progress
3139
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3140
 * configuration option can also be defined to override the default resampling
3141
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3142
 *
3143
 * @return CE_Failure if the access fails, otherwise CE_None.
3144
 */
3145
3146
CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3147
                             int nXSize, int nYSize, void *pData, int nBufXSize,
3148
                             int nBufYSize, GDALDataType eBufType,
3149
                             int nBandCount, const int *panBandMap,
3150
                             GSpacing nPixelSpace, GSpacing nLineSpace,
3151
                             GSpacing nBandSpace,
3152
                             GDALRasterIOExtraArg *psExtraArg)
3153
3154
0
{
3155
0
    GDALRasterIOExtraArg sExtraArg;
3156
0
    if (psExtraArg == nullptr)
3157
0
    {
3158
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3159
3160
        // 4 below inits are not strictly needed but make Coverity Scan
3161
        // happy
3162
0
        sExtraArg.dfXOff = nXOff;
3163
0
        sExtraArg.dfYOff = nYOff;
3164
0
        sExtraArg.dfXSize = nXSize;
3165
0
        sExtraArg.dfYSize = nYSize;
3166
3167
0
        psExtraArg = &sExtraArg;
3168
0
    }
3169
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
3170
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3171
0
    {
3172
0
        ReportError(CE_Failure, CPLE_AppDefined,
3173
0
                    "Unhandled version of GDALRasterIOExtraArg");
3174
0
        return CE_Failure;
3175
0
    }
3176
3177
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3178
0
                                       nBufYSize);
3179
3180
0
    if (CPL_UNLIKELY(nullptr == pData))
3181
0
    {
3182
0
        ReportError(CE_Failure, CPLE_AppDefined,
3183
0
                    "The buffer into which the data should be read is null");
3184
0
        return CE_Failure;
3185
0
    }
3186
3187
    /* -------------------------------------------------------------------- */
3188
    /*      Do some validation of parameters.                               */
3189
    /* -------------------------------------------------------------------- */
3190
3191
0
    if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3192
0
    {
3193
0
        ReportError(
3194
0
            CE_Failure, CPLE_IllegalArg,
3195
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3196
0
            eRWFlag);
3197
0
        return CE_Failure;
3198
0
    }
3199
3200
0
    if (eRWFlag == GF_Write)
3201
0
    {
3202
0
        if (CPL_UNLIKELY(eAccess != GA_Update))
3203
0
        {
3204
0
            ReportError(CE_Failure, CPLE_AppDefined,
3205
0
                        "Write operation not permitted on dataset opened "
3206
0
                        "in read-only mode");
3207
0
            return CE_Failure;
3208
0
        }
3209
0
    }
3210
3211
0
    int bStopProcessing = FALSE;
3212
0
    CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3213
0
        "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3214
0
        nBufYSize, nBandCount, panBandMap);
3215
0
    if (eErr != CE_None || bStopProcessing)
3216
0
        return eErr;
3217
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3218
0
    {
3219
0
        ReportError(CE_Failure, CPLE_AppDefined,
3220
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
3221
0
        return CE_Failure;
3222
0
    }
3223
3224
    /* -------------------------------------------------------------------- */
3225
    /*      If pixel and line spacing are defaulted assign reasonable      */
3226
    /*      value assuming a packed buffer.                                 */
3227
    /* -------------------------------------------------------------------- */
3228
0
    if (nPixelSpace == 0)
3229
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3230
3231
0
    if (nLineSpace == 0)
3232
0
    {
3233
0
        nLineSpace = nPixelSpace * nBufXSize;
3234
0
    }
3235
3236
0
    if (nBandSpace == 0 && nBandCount > 1)
3237
0
    {
3238
0
        nBandSpace = nLineSpace * nBufYSize;
3239
0
    }
3240
3241
0
    if (panBandMap == nullptr)
3242
0
    {
3243
0
        if (!m_poPrivate)
3244
0
            return CE_Failure;
3245
0
        CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3246
0
        panBandMap = m_poPrivate->m_anBandMap.data();
3247
0
    }
3248
3249
0
    int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3250
3251
    /* -------------------------------------------------------------------- */
3252
    /*      We are being forced to use cached IO instead of a driver        */
3253
    /*      specific implementation.                                        */
3254
    /* -------------------------------------------------------------------- */
3255
0
    if (bForceCachedIO)
3256
0
    {
3257
0
        eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3258
0
                                  nBufXSize, nBufYSize, eBufType, nBandCount,
3259
0
                                  panBandMap, nPixelSpace, nLineSpace,
3260
0
                                  nBandSpace, psExtraArg);
3261
0
    }
3262
3263
    /* -------------------------------------------------------------------- */
3264
    /*      Call the format specific function.                              */
3265
    /* -------------------------------------------------------------------- */
3266
0
    else
3267
0
    {
3268
0
        eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3269
0
                         nBufXSize, nBufYSize, eBufType, nBandCount,
3270
                         // TODO: remove this const_cast once IRasterIO()
3271
                         // takes a const int*
3272
0
                         const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3273
0
                         nBandSpace, psExtraArg);
3274
0
    }
3275
3276
0
    if (bCallLeaveReadWrite)
3277
0
        LeaveReadWrite();
3278
3279
0
    return eErr;
3280
0
}
3281
3282
/************************************************************************/
3283
/*                        GDALDatasetRasterIO()                         */
3284
/************************************************************************/
3285
3286
/**
3287
 * \brief Read/write a region of image data from multiple bands.
3288
 *
3289
 * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3290
 * resolution, progress callback, etc. are needed)
3291
 *
3292
 * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3293
 *
3294
 * @see GDALDataset::RasterIO()
3295
 */
3296
3297
CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3298
                                       int nXOff, int nYOff, int nXSize,
3299
                                       int nYSize, void *pData, int nBufXSize,
3300
                                       int nBufYSize, GDALDataType eBufType,
3301
                                       int nBandCount, const int *panBandMap,
3302
                                       int nPixelSpace, int nLineSpace,
3303
                                       int nBandSpace)
3304
3305
0
{
3306
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3307
3308
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3309
3310
0
    return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3311
0
                          nBufXSize, nBufYSize, eBufType, nBandCount,
3312
0
                          panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3313
0
                          nullptr);
3314
0
}
3315
3316
/************************************************************************/
3317
/*                       GDALDatasetRasterIOEx()                        */
3318
/************************************************************************/
3319
3320
/**
3321
 * \brief Read/write a region of image data from multiple bands.
3322
 *
3323
 * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3324
 *
3325
 * @see GDALDataset::RasterIO()
3326
 */
3327
3328
CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3329
    GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3330
    int nYSize, void *pData, int nBufXSize, int nBufYSize,
3331
    GDALDataType eBufType, int nBandCount, const int *panBandMap,
3332
    GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3333
    GDALRasterIOExtraArg *psExtraArg)
3334
3335
0
{
3336
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3337
3338
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3339
3340
0
    return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3341
0
                          nBufXSize, nBufYSize, eBufType, nBandCount,
3342
0
                          panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3343
0
                          psExtraArg);
3344
0
}
3345
3346
/************************************************************************/
3347
/*                          GetOpenDatasets()                           */
3348
/************************************************************************/
3349
3350
/**
3351
 * \brief Fetch all open GDAL dataset handles.
3352
 *
3353
 * This method is the same as the C function GDALGetOpenDatasets().
3354
 *
3355
 * NOTE: This method is not thread safe.  The returned list may change
3356
 * at any time and it should not be freed.
3357
 *
3358
 * @param pnCount integer into which to place the count of dataset pointers
3359
 * being returned.
3360
 *
3361
 * @return a pointer to an array of dataset handles.
3362
 */
3363
3364
GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3365
3366
0
{
3367
0
    CPLMutexHolderD(&hDLMutex);
3368
3369
0
    if (poAllDatasetMap == nullptr)
3370
0
    {
3371
0
        *pnCount = 0;
3372
0
        return nullptr;
3373
0
    }
3374
3375
0
    *pnCount = static_cast<int>(poAllDatasetMap->size());
3376
0
    ppDatasets = static_cast<GDALDataset **>(
3377
0
        CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3378
0
    std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3379
0
    for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3380
0
        ppDatasets[i] = oIter->first;
3381
0
    return ppDatasets;
3382
0
}
3383
3384
/************************************************************************/
3385
/*                        GDALGetOpenDatasets()                         */
3386
/************************************************************************/
3387
3388
/**
3389
 * \brief Fetch all open GDAL dataset handles.
3390
 *
3391
 * @see GDALDataset::GetOpenDatasets()
3392
 */
3393
3394
void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3395
3396
0
{
3397
0
    VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3398
0
    VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3399
3400
0
    *ppahDSList =
3401
0
        reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3402
0
}
3403
3404
/************************************************************************/
3405
/*                     GDALCleanOpenDatasetsList()                      */
3406
/************************************************************************/
3407
3408
// Useful when called from the child of a fork(), to avoid closing
3409
// the datasets of the parent at the child termination.
3410
void GDALNullifyOpenDatasetsList()
3411
0
{
3412
0
    poAllDatasetMap = nullptr;
3413
0
    phSharedDatasetSet = nullptr;
3414
0
    ppDatasets = nullptr;
3415
0
    hDLMutex = nullptr;
3416
0
}
3417
3418
/************************************************************************/
3419
/*                           GDALGetAccess()                            */
3420
/************************************************************************/
3421
3422
/**
3423
 * \brief Return access flag
3424
 *
3425
 * @see GDALDataset::GetAccess()
3426
 */
3427
3428
int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3429
0
{
3430
0
    VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3431
3432
0
    return GDALDataset::FromHandle(hDS)->GetAccess();
3433
0
}
3434
3435
/************************************************************************/
3436
/*                             AdviseRead()                             */
3437
/************************************************************************/
3438
3439
/**
3440
 * \brief Advise driver of upcoming read requests.
3441
 *
3442
 * Some GDAL drivers operate more efficiently if they know in advance what
3443
 * set of upcoming read requests will be made.  The AdviseRead() method allows
3444
 * an application to notify the driver of the region and bands of interest,
3445
 * and at what resolution the region will be read.
3446
 *
3447
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
3448
 * accelerate access via some drivers.
3449
 *
3450
 * Depending on call paths, drivers might receive several calls to
3451
 * AdviseRead() with the same parameters.
3452
 *
3453
 * @param nXOff The pixel offset to the top left corner of the region
3454
 * of the band to be accessed.  This would be zero to start from the left side.
3455
 *
3456
 * @param nYOff The line offset to the top left corner of the region
3457
 * of the band to be accessed.  This would be zero to start from the top.
3458
 *
3459
 * @param nXSize The width of the region of the band to be accessed in pixels.
3460
 *
3461
 * @param nYSize The height of the region of the band to be accessed in lines.
3462
 *
3463
 * @param nBufXSize the width of the buffer image into which the desired region
3464
 * is to be read, or from which it is to be written.
3465
 *
3466
 * @param nBufYSize the height of the buffer image into which the desired
3467
 * region is to be read, or from which it is to be written.
3468
 *
3469
 * @param eBufType the type of the pixel values in the pData data buffer.  The
3470
 * pixel values will automatically be translated to/from the GDALRasterBand
3471
 * data type as needed.
3472
 *
3473
 * @param nBandCount the number of bands being read or written.
3474
 *
3475
 * @param panBandMap the list of nBandCount band numbers being read/written.
3476
 * Note band numbers are 1 based.   This may be NULL to select the first
3477
 * nBandCount bands.
3478
 *
3479
 * @param papszOptions a list of name=value strings with special control
3480
 * options.  Normally this is NULL.
3481
 *
3482
 * @return CE_Failure if the request is invalid and CE_None if it works or
3483
 * is ignored.
3484
 */
3485
3486
CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3487
                               int nBufXSize, int nBufYSize,
3488
                               GDALDataType eBufType, int nBandCount,
3489
                               int *panBandMap, CSLConstList papszOptions)
3490
3491
0
{
3492
    /* -------------------------------------------------------------------- */
3493
    /*      Do some validation of parameters.                               */
3494
    /* -------------------------------------------------------------------- */
3495
0
    int bStopProcessing = FALSE;
3496
0
    CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3497
0
        "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3498
0
        nBufXSize, nBufYSize, nBandCount, panBandMap);
3499
0
    if (eErr != CE_None || bStopProcessing)
3500
0
        return eErr;
3501
3502
0
    for (int iBand = 0; iBand < nBandCount; ++iBand)
3503
0
    {
3504
0
        GDALRasterBand *poBand = nullptr;
3505
3506
0
        if (panBandMap == nullptr)
3507
0
            poBand = GetRasterBand(iBand + 1);
3508
0
        else
3509
0
            poBand = GetRasterBand(panBandMap[iBand]);
3510
3511
0
        if (poBand == nullptr)
3512
0
            return CE_Failure;
3513
3514
0
        eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3515
0
                                  nBufYSize, eBufType, papszOptions);
3516
3517
0
        if (eErr != CE_None)
3518
0
            return eErr;
3519
0
    }
3520
3521
0
    return CE_None;
3522
0
}
3523
3524
/************************************************************************/
3525
/*                       GDALDatasetAdviseRead()                        */
3526
/************************************************************************/
3527
3528
/**
3529
 * \brief Advise driver of upcoming read requests.
3530
 *
3531
 * @see GDALDataset::AdviseRead()
3532
 */
3533
CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3534
                                         int nXSize, int nYSize, int nBufXSize,
3535
                                         int nBufYSize, GDALDataType eDT,
3536
                                         int nBandCount, int *panBandMap,
3537
                                         CSLConstList papszOptions)
3538
3539
0
{
3540
0
    VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3541
3542
0
    return GDALDataset::FromHandle(hDS)->AdviseRead(
3543
0
        nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3544
0
        panBandMap, const_cast<char **>(papszOptions));
3545
0
}
3546
3547
/************************************************************************/
3548
/*                       GDALAntiRecursionStruct                        */
3549
/************************************************************************/
3550
3551
// Prevent infinite recursion.
3552
struct GDALAntiRecursionStruct
3553
{
3554
    struct DatasetContext
3555
    {
3556
        std::string osFilename;
3557
        int nOpenFlags;
3558
        std::string osAllowedDrivers;
3559
3560
        DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3561
                       const std::string &osAllowedDriversIn)
3562
0
            : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3563
0
              osAllowedDrivers(osAllowedDriversIn)
3564
0
        {
3565
0
        }
3566
    };
3567
3568
    struct DatasetContextCompare
3569
    {
3570
        bool operator()(const DatasetContext &lhs,
3571
                        const DatasetContext &rhs) const
3572
0
        {
3573
0
            return lhs.osFilename < rhs.osFilename ||
3574
0
                   (lhs.osFilename == rhs.osFilename &&
3575
0
                    (lhs.nOpenFlags < rhs.nOpenFlags ||
3576
0
                     (lhs.nOpenFlags == rhs.nOpenFlags &&
3577
0
                      lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3578
0
        }
3579
    };
3580
3581
    ~GDALAntiRecursionStruct()
3582
0
    {
3583
0
        CPLAssert(aosDatasetNamesWithFlags.empty());
3584
0
        CPLAssert(nRecLevel == 0);
3585
0
        CPLAssert(m_oMapDepth.empty());
3586
0
    }
3587
3588
    std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3589
    int nRecLevel = 0;
3590
    std::map<std::string, int> m_oMapDepth{};
3591
};
3592
3593
#ifdef _WIN32
3594
// Currently thread_local and C++ objects don't work well with DLL on Windows
3595
static void FreeAntiRecursionOpen(void *pData)
3596
{
3597
    delete static_cast<GDALAntiRecursionStruct *>(pData);
3598
}
3599
3600
static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3601
{
3602
    static GDALAntiRecursionStruct dummy;
3603
    int bMemoryErrorOccurred = false;
3604
    void *pData =
3605
        CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3606
    if (bMemoryErrorOccurred)
3607
    {
3608
        return dummy;
3609
    }
3610
    if (pData == nullptr)
3611
    {
3612
        auto pAntiRecursion = new GDALAntiRecursionStruct();
3613
        CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3614
                                FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3615
        if (bMemoryErrorOccurred)
3616
        {
3617
            delete pAntiRecursion;
3618
            return dummy;
3619
        }
3620
        return *pAntiRecursion;
3621
    }
3622
    return *static_cast<GDALAntiRecursionStruct *>(pData);
3623
}
3624
#else
3625
static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3626
3627
static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3628
0
{
3629
0
    return g_tls_antiRecursion;
3630
0
}
3631
#endif
3632
3633
//! @cond Doxygen_Suppress
3634
GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3635
0
    : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3636
0
      m_osIdentifier(osIdentifier),
3637
0
      m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3638
0
{
3639
0
    CPLAssert(!osIdentifier.empty());
3640
0
}
3641
3642
GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3643
    const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3644
0
    : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3645
0
      m_osIdentifier(osIdentifier.empty()
3646
0
                         ? osIdentifier
3647
0
                         : other.m_osIdentifier + osIdentifier),
3648
0
      m_nDepth(m_osIdentifier.empty()
3649
0
                   ? 0
3650
0
                   : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3651
0
{
3652
0
}
3653
3654
GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3655
0
{
3656
0
    if (!m_osIdentifier.empty())
3657
0
    {
3658
0
        auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3659
0
        CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3660
0
        if (--(oIter->second) == 0)
3661
0
            m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3662
0
    }
3663
0
}
3664
3665
//! @endcond
3666
3667
/************************************************************************/
3668
/*                            GetFileList()                             */
3669
/************************************************************************/
3670
3671
/**
3672
 * \brief Fetch files forming dataset.
3673
 *
3674
 * Returns a list of files believed to be part of this dataset.  If it returns
3675
 * an empty list of files it means there is believed to be no local file
3676
 * system files associated with the dataset (for instance a virtual dataset).
3677
 * The returned file list is owned by the caller and should be deallocated
3678
 * with CSLDestroy().
3679
 *
3680
 * The returned filenames will normally be relative or absolute paths
3681
 * depending on the path used to originally open the dataset.  The strings
3682
 * will be UTF-8 encoded.
3683
 *
3684
 * This method is the same as the C GDALGetFileList() function.
3685
 *
3686
 * @return NULL or a NULL terminated array of file names.
3687
 */
3688
3689
char **GDALDataset::GetFileList()
3690
3691
0
{
3692
0
    CPLString osMainFilename = GetDescription();
3693
0
    VSIStatBufL sStat;
3694
3695
0
    GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3696
0
    GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3697
0
                                                        std::string());
3698
0
    auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3699
0
    if (cpl::contains(aosDatasetList, datasetCtxt))
3700
0
        return nullptr;
3701
3702
    /* -------------------------------------------------------------------- */
3703
    /*      Is the main filename even a real filesystem object?             */
3704
    /* -------------------------------------------------------------------- */
3705
0
    int bMainFileReal =
3706
0
        VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3707
3708
    /* -------------------------------------------------------------------- */
3709
    /*      Form new list.                                                  */
3710
    /* -------------------------------------------------------------------- */
3711
0
    char **papszList = nullptr;
3712
3713
0
    if (bMainFileReal)
3714
0
        papszList = CSLAddString(papszList, osMainFilename);
3715
3716
0
    if (sAntiRecursion.nRecLevel == 100)
3717
0
    {
3718
0
        CPLError(CE_Failure, CPLE_AppDefined,
3719
0
                 "GetFileList() called with too many recursion levels");
3720
0
        return papszList;
3721
0
    }
3722
0
    ++sAntiRecursion.nRecLevel;
3723
3724
    /* -------------------------------------------------------------------- */
3725
    /*      Do we have a known overview file?                               */
3726
    /* -------------------------------------------------------------------- */
3727
0
    if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3728
0
    {
3729
0
        auto iter = aosDatasetList.insert(datasetCtxt).first;
3730
0
        char **papszOvrList = oOvManager.poODS->GetFileList();
3731
0
        papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3732
0
        CSLDestroy(papszOvrList);
3733
0
        aosDatasetList.erase(iter);
3734
0
    }
3735
3736
    /* -------------------------------------------------------------------- */
3737
    /*      Do we have a known mask file?                                   */
3738
    /* -------------------------------------------------------------------- */
3739
0
    if (oOvManager.HaveMaskFile())
3740
0
    {
3741
0
        auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3742
0
        for (const char *pszFile :
3743
0
             CPLStringList(oOvManager.poMaskDS->GetFileList()))
3744
0
        {
3745
0
            if (CSLFindString(papszList, pszFile) < 0)
3746
0
                papszList = CSLAddString(papszList, pszFile);
3747
0
        }
3748
0
        aosDatasetList.erase(iter);
3749
0
    }
3750
3751
0
    --sAntiRecursion.nRecLevel;
3752
3753
0
    return papszList;
3754
0
}
3755
3756
/************************************************************************/
3757
/*                          GDALGetFileList()                           */
3758
/************************************************************************/
3759
3760
/**
3761
 * \brief Fetch files forming dataset.
3762
 *
3763
 * @see GDALDataset::GetFileList()
3764
 */
3765
3766
char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3767
3768
0
{
3769
0
    VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3770
3771
0
    return GDALDataset::FromHandle(hDS)->GetFileList();
3772
0
}
3773
3774
/************************************************************************/
3775
/*                           CreateMaskBand()                           */
3776
/************************************************************************/
3777
3778
/**
3779
 * \brief Adds a mask band to the dataset
3780
 *
3781
 * The default implementation of the CreateMaskBand() method is implemented
3782
 * based on similar rules to the .ovr handling implemented using the
3783
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3784
 * be created with the same basename as the original file, and it will have
3785
 * one band.
3786
 * The mask images will be deflate compressed tiled images with the same
3787
 * block size as the original image if possible.
3788
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3789
 * level, where xx matches the band number of a band of the main dataset. The
3790
 * value of those items will be the one of the nFlagsIn parameter.
3791
 *
3792
 * Note that if you got a mask band with a previous call to GetMaskBand(), it
3793
 * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3794
 * again.
3795
 *
3796
 *
3797
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3798
 *                 GMF_PER_DATASET will be always set, even if not explicitly
3799
 *                 specified.
3800
 * @return CE_None on success or CE_Failure on an error.
3801
 *
3802
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3803
 * @see GDALRasterBand::CreateMaskBand()
3804
 *
3805
 */
3806
CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3807
3808
0
{
3809
0
    if (oOvManager.IsInitialized())
3810
0
    {
3811
0
        CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3812
0
        if (eErr != CE_None)
3813
0
            return eErr;
3814
3815
        // Invalidate existing raster band masks.
3816
0
        for (int i = 0; i < nBands; ++i)
3817
0
        {
3818
0
            GDALRasterBand *poBand = papoBands[i];
3819
0
            poBand->poMask.reset();
3820
0
        }
3821
3822
0
        return CE_None;
3823
0
    }
3824
3825
0
    ReportError(CE_Failure, CPLE_NotSupported,
3826
0
                "CreateMaskBand() not supported for this dataset.");
3827
3828
0
    return CE_Failure;
3829
0
}
3830
3831
/************************************************************************/
3832
/*                     GDALCreateDatasetMaskBand()                      */
3833
/************************************************************************/
3834
3835
/**
3836
 * \brief Adds a mask band to the dataset
3837
 * @see GDALDataset::CreateMaskBand()
3838
 */
3839
CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3840
3841
0
{
3842
0
    VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3843
3844
0
    return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3845
0
}
3846
3847
/************************************************************************/
3848
/*                              GDALOpen()                              */
3849
/************************************************************************/
3850
3851
/**
3852
 * \brief Open a raster file as a GDALDataset.
3853
 *
3854
 * This function will try to open the passed file, or virtual dataset
3855
 * name by invoking the Open method of each registered GDALDriver in turn.
3856
 * The first successful open will result in a returned dataset.  If all
3857
 * drivers fail then NULL is returned and an error is issued.
3858
 *
3859
 * Several recommendations :
3860
 * <ul>
3861
 * <li>If you open a dataset object with GA_Update access, it is not recommended
3862
 * to open a new dataset on the same underlying file.</li>
3863
 * <li>The returned dataset should only be accessed by one thread at a time. If
3864
 * you want to use it from different threads, you must add all necessary code
3865
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
3866
 * as GeoTIFF, maintain internal state variables that are updated each time a
3867
 * new block is read, thus preventing concurrent use.) </li>
3868
 * </ul>
3869
 *
3870
 * For drivers supporting the VSI virtual file API, it is possible to open a
3871
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3872
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3873
 * server (see VSIInstallCurlFileHandler())
3874
 *
3875
 * \sa GDALOpenShared()
3876
 * \sa GDALOpenEx()
3877
 *
3878
 * @param pszFilename the name of the file to access.  In the case of
3879
 * exotic drivers this may not refer to a physical file, but instead contain
3880
 * information for the driver on how to access a dataset.  It should be in UTF-8
3881
 * encoding.
3882
 *
3883
 * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
3884
 * drivers support only read only access.
3885
 *
3886
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
3887
 * this handle can be cast to a GDALDataset *.
3888
 */
3889
3890
GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3891
3892
0
{
3893
0
    const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3894
0
    const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3895
0
    GDALDatasetH hDataset =
3896
0
        GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3897
0
    return hDataset;
3898
0
}
3899
3900
/************************************************************************/
3901
/*                            GetSharedDS()                             */
3902
/************************************************************************/
3903
3904
static GDALDataset *GetSharedDS(const char *pszFilename,
3905
                                unsigned int nOpenFlags,
3906
                                const char *const *papszOpenOptions)
3907
0
{
3908
0
    CPLMutexHolderD(&hDLMutex);
3909
3910
0
    if (phSharedDatasetSet != nullptr)
3911
0
    {
3912
0
        const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3913
0
        SharedDatasetCtxt sStruct;
3914
3915
0
        sStruct.nPID = nThisPID;
3916
0
        sStruct.pszDescription = const_cast<char *>(pszFilename);
3917
0
        sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3918
0
        std::string osConcatenatedOpenOptions =
3919
0
            GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3920
0
        sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3921
0
        sStruct.poDS = nullptr;
3922
0
        SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3923
0
            CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3924
0
        if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3925
0
        {
3926
0
            sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3927
0
            psStruct = static_cast<SharedDatasetCtxt *>(
3928
0
                CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3929
0
        }
3930
0
        if (psStruct)
3931
0
        {
3932
0
            return psStruct->poDS;
3933
0
        }
3934
0
    }
3935
0
    return nullptr;
3936
0
}
3937
3938
/************************************************************************/
3939
/*                             GDALOpenEx()                             */
3940
/************************************************************************/
3941
3942
/**
3943
 * \brief Open a raster or vector file as a GDALDataset.
3944
 *
3945
 * This function will try to open the passed file, or virtual dataset
3946
 * name by invoking the Open method of each registered GDALDriver in turn.
3947
 * The first successful open will result in a returned dataset.  If all
3948
 * drivers fail then NULL is returned and an error is issued.
3949
 *
3950
 * Several recommendations :
3951
 * <ul>
3952
 * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3953
 * recommended to open a new dataset on the same underlying file.</li>
3954
 * <li>The returned dataset should only be accessed by one thread at a time. If
3955
 * you want to use it from different threads, you must add all necessary code
3956
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
3957
 * as GeoTIFF, maintain internal state variables that are updated each time a
3958
 * new block is read, thus preventing concurrent use.) </li>
3959
 * </ul>
3960
 *
3961
 * For drivers supporting the VSI virtual file API, it is possible to open a
3962
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3963
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3964
 * server (see VSIInstallCurlFileHandler())
3965
 *
3966
 * In order to reduce the need for searches through the operating system
3967
 * file system machinery, it is possible to give an optional list of files with
3968
 * the papszSiblingFiles parameter.
3969
 * This is the list of all files at the same level in the file system as the
3970
 * target file, including the target file. The filenames must not include any
3971
 * path components, are essentially just the output of VSIReadDir() on the
3972
 * parent directory. If the target object does not have filesystem semantics
3973
 * then the file list should be NULL.
3974
 *
3975
 * @param pszFilename the name of the file to access.  In the case of
3976
 * exotic drivers this may not refer to a physical file, but instead contain
3977
 * information for the driver on how to access a dataset.  It should be in UTF-8
3978
 * encoding.
3979
 *
3980
 * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3981
 * through logical or operator.
3982
 * <ul>
3983
 * <li>Driver kind:
3984
 *   <ul>
3985
 *     <li>GDAL_OF_RASTER for raster drivers,</li>
3986
 *     <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3987
 *     <li>GDAL_OF_VECTOR for vector drivers,</li>
3988
 *     <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3989
 *    </ul>
3990
 * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3991
 * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3992
 * | GDAL_OF_GNM is implied.
3993
 * </li>
3994
 * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3995
 * </li>
3996
 * <li>Shared mode: GDAL_OF_SHARED. If set,
3997
 * it allows the sharing of GDALDataset handles for a dataset with other callers
3998
 * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
3999
 * its list of currently open and shared GDALDataset's, and if the
4000
 * GetDescription() name for one exactly matches the pszFilename passed to
4001
 * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
4002
 * from the same thread.
4003
 * </li>
4004
 * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
4005
 * This must be use in combination with GDAL_OF_RASTER, and is mutually
4006
 * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4007
 * GDAL_OF_GNM.
4008
 * </li>
4009
 * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4010
 * a failed attempt to open the file will lead to an error message to be
4011
 * reported.
4012
 * </li>
4013
 * </ul>
4014
 *
4015
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4016
 * terminated list of strings with the driver short names that must be
4017
 * considered.
4018
 * Starting with GDAL 3.13, a string starting with the dash (-) character
4019
 * followed by the driver short name can be used to exclude a driver.
4020
 *
4021
 * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4022
 * options passed to candidate drivers. An option exists for all drivers,
4023
 * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4024
 * The level index starts at 0. The level number can be suffixed by "only" to
4025
 * specify that only this overview level must be visible, and not sub-levels.
4026
 * Open options are validated by default, and a warning is emitted in case the
4027
 * option is not recognized. In some scenarios, it might be not desirable (e.g.
4028
 * when not knowing which driver will open the file), so the special open option
4029
 * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4030
 * that it may not cause a warning if the driver doesn't declare this option.
4031
 * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4032
 * no overviews should be exposed.
4033
 *
4034
 * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4035
 * filenames that are auxiliary to the main filename. If NULL is passed, a
4036
 * probing of the file system will be done.
4037
 *
4038
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
4039
 * this handle can be cast to a GDALDataset *.
4040
 *
4041
 */
4042
4043
GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4044
                                    unsigned int nOpenFlags,
4045
                                    const char *const *papszAllowedDrivers,
4046
                                    const char *const *papszOpenOptions,
4047
                                    const char *const *papszSiblingFiles)
4048
0
{
4049
0
    VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4050
4051
    // Do some sanity checks on incompatible flags with thread-safe mode.
4052
0
    if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4053
0
    {
4054
0
        const struct
4055
0
        {
4056
0
            int nFlag;
4057
0
            const char *pszFlagName;
4058
0
        } asFlags[] = {
4059
0
            {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4060
0
            {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4061
0
            {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4062
0
            {GDAL_OF_GNM, "GDAL_OF_GNM"},
4063
0
        };
4064
4065
0
        for (const auto &asFlag : asFlags)
4066
0
        {
4067
0
            if ((nOpenFlags & asFlag.nFlag) != 0)
4068
0
            {
4069
0
                CPLError(CE_Failure, CPLE_IllegalArg,
4070
0
                         "GDAL_OF_THREAD_SAFE and %s are mutually "
4071
0
                         "exclusive",
4072
0
                         asFlag.pszFlagName);
4073
0
                return nullptr;
4074
0
            }
4075
0
        }
4076
0
    }
4077
4078
    // If no driver kind is specified, assume all are to be probed.
4079
0
    if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4080
0
        nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4081
4082
    /* -------------------------------------------------------------------- */
4083
    /*      In case of shared dataset, first scan the existing list to see  */
4084
    /*      if it could already contain the requested dataset.              */
4085
    /* -------------------------------------------------------------------- */
4086
0
    if (nOpenFlags & GDAL_OF_SHARED)
4087
0
    {
4088
0
        if (nOpenFlags & GDAL_OF_INTERNAL)
4089
0
        {
4090
0
            CPLError(CE_Failure, CPLE_IllegalArg,
4091
0
                     "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4092
0
            return nullptr;
4093
0
        }
4094
4095
0
        auto poSharedDS =
4096
0
            GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4097
0
        if (poSharedDS)
4098
0
        {
4099
0
            poSharedDS->Reference();
4100
0
            return poSharedDS;
4101
0
        }
4102
0
    }
4103
4104
0
    CPLErrorReset();
4105
0
    VSIErrorReset();
4106
4107
    // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4108
    // shared dataset was asked before.
4109
0
    GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4110
4111
0
    return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4112
0
        .release();
4113
0
}
4114
4115
/************************************************************************/
4116
/*                         GDALDataset::Open()                          */
4117
/************************************************************************/
4118
4119
/**
4120
 * \brief Open a raster or vector file as a GDALDataset.
4121
 *
4122
 * This function will use the passed open info on each registered GDALDriver in
4123
 * turn.
4124
 * The first successful open will result in a returned dataset.  If all
4125
 * drivers fail then NULL is returned and an error is issued.
4126
 *
4127
 * Several recommendations :
4128
 * <ul>
4129
 * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4130
 * recommended to open a new dataset on the same underlying file.</li>
4131
 * <li>The returned dataset should only be accessed by one thread at a time. If
4132
 * you want to use it from different threads, you must add all necessary code
4133
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
4134
 * as GeoTIFF, maintain internal state variables that are updated each time a
4135
 * new block is read, thus preventing concurrent use.) </li>
4136
 * </ul>
4137
 *
4138
 * For drivers supporting the VSI virtual file API, it is possible to open a
4139
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4140
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4141
 * server (see VSIInstallCurlFileHandler())
4142
 *
4143
 * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4144
 * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4145
 * If shared dataset is needed, use GDALOpenEx() or the other variant of
4146
 * GDALDataset::Open()
4147
 *
4148
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4149
 * terminated list of strings with the driver short names that must be
4150
 * considered.
4151
 * Starting with GDAL 3.13, a string starting with the dash (-) character
4152
 * followed by the driver short name can be used to exclude a driver.
4153
 *
4154
 * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4155
 * options passed to candidate drivers. An option exists for all drivers,
4156
 * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4157
 * The level index starts at 0. The level number can be suffixed by "only" to
4158
 * specify that only this overview level must be visible, and not sub-levels.
4159
 * Open options are validated by default, and a warning is emitted in case the
4160
 * option is not recognized. In some scenarios, it might be not desirable (e.g.
4161
 * when not knowing which driver will open the file), so the special open option
4162
 * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4163
 * that it may not cause a warning if the driver doesn't declare this option.
4164
 * OVERVIEW_LEVEL=NONE is supported to indicate that
4165
 * no overviews should be exposed.
4166
 *
4167
 * @return A GDALDataset unique pointer or NULL on failure.
4168
 *
4169
 * @since 3.13
4170
 */
4171
4172
std::unique_ptr<GDALDataset>
4173
GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4174
                  const char *const *papszAllowedDrivers,
4175
                  const char *const *papszOpenOptions)
4176
0
{
4177
    // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4178
    // into VSIKERCHUNK_USE_CACHE config option
4179
0
    std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4180
0
    if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4181
0
    {
4182
0
        poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4183
0
            "VSIKERCHUNK_USE_CACHE", "YES", false);
4184
0
    }
4185
4186
0
    GDALDriverManager *poDM = GetGDALDriverManager();
4187
4188
0
    CPLAssert(nullptr != poDM);
4189
4190
0
    GDALOpenInfo &oOpenInfo = *poOpenInfo;
4191
0
    const char *pszFilename = poOpenInfo->pszFilename;
4192
0
    const int nOpenFlags = poOpenInfo->nOpenFlags;
4193
0
    oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4194
4195
0
    GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4196
0
    if (sAntiRecursion.nRecLevel == 100)
4197
0
    {
4198
0
        CPLError(CE_Failure, CPLE_AppDefined,
4199
0
                 "GDALOpen() called with too many recursion levels");
4200
0
        return nullptr;
4201
0
    }
4202
4203
0
    std::string osAllowedDrivers;
4204
0
    for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4205
0
        osAllowedDrivers += pszDriverName;
4206
0
    auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4207
0
        std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4208
0
    if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4209
0
    {
4210
0
        CPLError(CE_Failure, CPLE_AppDefined,
4211
0
                 "GDALOpen() called on %s recursively", pszFilename);
4212
0
        return nullptr;
4213
0
    }
4214
4215
    // Remove leading @ if present.
4216
0
    char **papszOpenOptionsCleaned =
4217
0
        CSLDuplicate(const_cast<char **>(papszOpenOptions));
4218
0
    for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4219
0
         ++papszIter)
4220
0
    {
4221
0
        char *pszOption = *papszIter;
4222
0
        if (pszOption[0] == '@')
4223
0
            memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4224
0
    }
4225
4226
0
    oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4227
0
    oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4228
4229
0
#ifdef OGRAPISPY_ENABLED
4230
0
    const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4231
0
    const int iSnapshot =
4232
0
        (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4233
0
            ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4234
0
            : INT_MIN;
4235
0
#endif
4236
4237
0
    const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4238
0
    GDALDriver *poMissingPluginDriver = nullptr;
4239
0
    std::vector<GDALDriver *> apoSecondPassDrivers;
4240
4241
    // Lookup of matching driver for dataset can involve up to 2 passes:
4242
    // - in the first pass, all drivers that are compabile of the request mode
4243
    //   (raster/vector/etc.) are probed using their Identify() method if it
4244
    //   exists. If the Identify() method returns FALSE, the driver is skipped.
4245
    //   If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4246
    //   driver is a deferred-loading plugin, it is added to the
4247
    //   apoSecondPassDrivers list for potential later probing, and execution
4248
    //   continues to the next driver in the list.
4249
    //   Otherwise if Identify() returns non-FALSE, the Open() method is used.
4250
    //   If Open() returns a non-NULL dataset, the loop stops and it is
4251
    //   returned. Otherwise looping over remaining drivers continues.
4252
    // - the second pass is optional, only if at least one driver was added
4253
    //   into apoSecondPassDrivers during the first pass. It is similar
4254
    //   to the first pass except it runs only on apoSecondPassDrivers drivers.
4255
    //   And the Open() method of such drivers is used, causing them to be
4256
    //   loaded for real.
4257
0
    int iPass = 1;
4258
0
retry:
4259
0
    for (int iDriver = 0;
4260
0
         iDriver < (iPass == 1 ? nDriverCount
4261
0
                               : static_cast<int>(apoSecondPassDrivers.size()));
4262
0
         ++iDriver)
4263
0
    {
4264
0
        GDALDriver *poDriver =
4265
0
            iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4266
0
                       : apoSecondPassDrivers[iDriver];
4267
0
        const char *pszDriverName = GDALGetDriverShortName(poDriver);
4268
0
        if (pszDriverName && papszAllowedDrivers)
4269
0
        {
4270
0
            bool bDriverMatchedPositively = false;
4271
0
            bool bDriverMatchedNegatively = false;
4272
0
            bool bOnlyExcludedDrivers = true;
4273
0
            for (const char *pszAllowedDriver :
4274
0
                 cpl::Iterate(papszAllowedDrivers))
4275
0
            {
4276
0
                if (pszAllowedDriver[0] != '-')
4277
0
                    bOnlyExcludedDrivers = false;
4278
0
                if (EQUAL(pszAllowedDriver, pszDriverName))
4279
0
                {
4280
0
                    bDriverMatchedPositively = true;
4281
0
                }
4282
0
                else if (pszAllowedDriver[0] == '-' &&
4283
0
                         EQUAL(pszAllowedDriver + 1, pszDriverName))
4284
0
                {
4285
0
                    bDriverMatchedNegatively = true;
4286
0
                    break;
4287
0
                }
4288
0
            }
4289
0
            if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4290
0
                bDriverMatchedNegatively)
4291
0
            {
4292
0
                continue;
4293
0
            }
4294
0
        }
4295
4296
0
        if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4297
0
            continue;
4298
4299
0
        if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4300
0
            (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4301
0
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4302
0
            continue;
4303
0
        if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4304
0
            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4305
0
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4306
0
            continue;
4307
0
        if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4308
0
            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4309
0
            poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4310
0
            continue;
4311
4312
        // Remove general OVERVIEW_LEVEL open options from list before passing
4313
        // it to the driver, if it isn't a driver specific option already.
4314
0
        char **papszTmpOpenOptions = nullptr;
4315
0
        char **papszTmpOpenOptionsToValidate = nullptr;
4316
0
        char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4317
0
        if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4318
0
                nullptr &&
4319
0
            !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4320
0
        {
4321
0
            papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4322
0
            papszTmpOpenOptions =
4323
0
                CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4324
0
            oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4325
4326
0
            papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4327
0
            papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4328
0
                                                     "OVERVIEW_LEVEL", nullptr);
4329
0
            papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4330
0
        }
4331
4332
0
        const int nIdentifyRes =
4333
0
            poDriver->pfnIdentifyEx
4334
0
                ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4335
0
            : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4336
0
                                    : GDAL_IDENTIFY_UNKNOWN;
4337
0
        if (nIdentifyRes == FALSE)
4338
0
        {
4339
0
            CSLDestroy(papszTmpOpenOptions);
4340
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4341
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4342
0
            continue;
4343
0
        }
4344
0
        else if (iPass == 1 && nIdentifyRes < 0 &&
4345
0
                 poDriver->pfnOpen == nullptr &&
4346
0
                 poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4347
0
        {
4348
            // Not loaded plugin
4349
0
            apoSecondPassDrivers.push_back(poDriver);
4350
0
            CSLDestroy(papszTmpOpenOptions);
4351
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4352
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4353
0
            continue;
4354
0
        }
4355
4356
0
        const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4357
0
        if (bIdentifyRes)
4358
0
        {
4359
0
            GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4360
0
        }
4361
4362
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4363
0
        const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4364
0
        CPLErrorReset();
4365
0
#endif
4366
4367
0
        sAntiRecursion.nRecLevel++;
4368
0
        sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4369
4370
0
        GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4371
4372
0
        sAntiRecursion.nRecLevel--;
4373
0
        sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4374
4375
0
        if (poDriver->pfnOpen != nullptr)
4376
0
        {
4377
            // If we couldn't determine for sure with Identify() (it returned
4378
            // -1), but Open() managed to open the file, post validate options.
4379
0
            if (poDS != nullptr &&
4380
0
                (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4381
0
                !bIdentifyRes)
4382
0
            {
4383
0
                GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4384
0
            }
4385
0
        }
4386
0
        else if (poDriver->pfnOpenWithDriverArg != nullptr)
4387
0
        {
4388
            // do nothing
4389
0
        }
4390
0
        else if (bIdentifyRes &&
4391
0
                 poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4392
0
        {
4393
0
            if (!poMissingPluginDriver)
4394
0
            {
4395
0
                poMissingPluginDriver = poDriver;
4396
0
            }
4397
0
        }
4398
0
        else
4399
0
        {
4400
            // should not happen given the GDAL_DCAP_OPEN check
4401
0
            CSLDestroy(papszTmpOpenOptions);
4402
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4403
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4404
0
            continue;
4405
0
        }
4406
4407
0
        CSLDestroy(papszTmpOpenOptions);
4408
0
        CSLDestroy(papszTmpOpenOptionsToValidate);
4409
0
        oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4410
4411
0
        if (poDS != nullptr)
4412
0
        {
4413
0
            if (poDS->papszOpenOptions == nullptr)
4414
0
            {
4415
0
                poDS->papszOpenOptions = papszOpenOptionsCleaned;
4416
0
                papszOpenOptionsCleaned = nullptr;
4417
0
            }
4418
4419
            // Deal with generic OVERVIEW_LEVEL open option, unless it is
4420
            // driver specific.
4421
0
            if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4422
0
                    nullptr &&
4423
0
                !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4424
0
            {
4425
0
                CPLString osVal(
4426
0
                    CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4427
0
                const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4428
0
                const bool bThisLevelOnly =
4429
0
                    nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4430
0
                GDALDataset *poOvrDS =
4431
0
                    GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4432
0
                if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4433
0
                {
4434
0
                    if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4435
0
                    {
4436
0
                        CPLError(
4437
0
                            CE_Warning, CPLE_NotSupported,
4438
0
                            "A dataset opened by GDALOpenShared should have "
4439
0
                            "the same filename (%s) "
4440
0
                            "and description (%s)",
4441
0
                            pszFilename, poDS->GetDescription());
4442
0
                    }
4443
0
                    else
4444
0
                    {
4445
0
                        CSLDestroy(poDS->papszOpenOptions);
4446
0
                        poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4447
0
                        poDS->papszOpenOptions = CSLSetNameValue(
4448
0
                            poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4449
0
                    }
4450
0
                }
4451
0
                poDS->ReleaseRef();
4452
0
                poDS = poOvrDS;
4453
0
                if (poDS == nullptr)
4454
0
                {
4455
0
                    if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4456
0
                    {
4457
0
                        CPLError(CE_Failure, CPLE_OpenFailed,
4458
0
                                 "Cannot open overview level %d of %s",
4459
0
                                 nOvrLevel, pszFilename);
4460
0
                    }
4461
0
                }
4462
0
                else
4463
0
                {
4464
                    // For thread-safe opening, currently poDS is what will be
4465
                    // the "master" dataset owned by the thread-safe dataset
4466
                    // returned to the user, hence we do not register it as a
4467
                    // visible one in the open dataset list, or mark it as shared.
4468
0
                    if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4469
0
                        !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4470
0
                    {
4471
0
                        poDS->AddToDatasetOpenList();
4472
0
                    }
4473
0
                    if (nOpenFlags & GDAL_OF_SHARED)
4474
0
                    {
4475
0
                        CSLDestroy(poDS->papszOpenOptions);
4476
0
                        poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4477
0
                        poDS->nOpenFlags = nOpenFlags;
4478
0
                        if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4479
0
                            poDS->MarkAsShared();
4480
0
                    }
4481
0
                }
4482
0
            }
4483
0
            else if (nOpenFlags & GDAL_OF_SHARED)
4484
0
            {
4485
0
                if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4486
0
                {
4487
0
                    CPLError(CE_Warning, CPLE_NotSupported,
4488
0
                             "A dataset opened by GDALOpenShared should have "
4489
0
                             "the same filename (%s) "
4490
0
                             "and description (%s)",
4491
0
                             pszFilename, poDS->GetDescription());
4492
0
                }
4493
0
                else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4494
0
                {
4495
                    // For thread-safe opening, currently poDS is what will be
4496
                    // the "master" dataset owned by the thread-safe dataset
4497
                    // returned to the user, hence we do not or mark it as shared.
4498
0
                    poDS->MarkAsShared();
4499
0
                }
4500
0
            }
4501
4502
0
            VSIErrorReset();
4503
4504
0
            CSLDestroy(papszOpenOptionsCleaned);
4505
4506
0
#ifdef OGRAPISPY_ENABLED
4507
0
            if (iSnapshot != INT_MIN)
4508
0
            {
4509
0
                GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4510
0
                OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4511
0
                poDS = GDALDataset::FromHandle(hDS);
4512
0
            }
4513
0
#endif
4514
4515
0
            if (poDS)
4516
0
            {
4517
0
                poDS->m_bCanBeReopened = true;
4518
4519
0
                if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4520
0
                {
4521
0
                    poDS =
4522
0
                        GDALGetThreadSafeDataset(
4523
0
                            std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4524
0
                            .release();
4525
0
                    if (poDS)
4526
0
                    {
4527
0
                        poDS->m_bCanBeReopened = true;
4528
0
                        poDS->poDriver = poDriver;
4529
0
                        poDS->nOpenFlags = nOpenFlags;
4530
0
                        if (!(nOpenFlags & GDAL_OF_INTERNAL))
4531
0
                            poDS->AddToDatasetOpenList();
4532
0
                        if (nOpenFlags & GDAL_OF_SHARED)
4533
0
                            poDS->MarkAsShared();
4534
0
                    }
4535
0
                }
4536
0
            }
4537
4538
0
            return std::unique_ptr<GDALDataset>(poDS);
4539
0
        }
4540
4541
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4542
0
        if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4543
0
        {
4544
            // In case the file descriptor was "consumed" by a driver
4545
            // that ultimately failed, re-open it for next drivers.
4546
0
            oOpenInfo.fpL = VSIFOpenL(
4547
0
                pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4548
0
        }
4549
#else
4550
        if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4551
        {
4552
            CSLDestroy(papszOpenOptionsCleaned);
4553
4554
#ifdef OGRAPISPY_ENABLED
4555
            if (iSnapshot != INT_MIN)
4556
            {
4557
                GDALDatasetH hDS = nullptr;
4558
                OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4559
            }
4560
#endif
4561
            return nullptr;
4562
        }
4563
#endif
4564
0
    }
4565
4566
    // cppcheck-suppress knownConditionTrueFalse
4567
0
    if (iPass == 1 && !apoSecondPassDrivers.empty())
4568
0
    {
4569
0
        CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4570
0
        iPass = 2;
4571
0
        goto retry;
4572
0
    }
4573
4574
0
    CSLDestroy(papszOpenOptionsCleaned);
4575
4576
0
#ifdef OGRAPISPY_ENABLED
4577
0
    if (iSnapshot != INT_MIN)
4578
0
    {
4579
0
        GDALDatasetH hDS = nullptr;
4580
0
        OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4581
0
    }
4582
0
#endif
4583
4584
0
    if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4585
0
    {
4586
0
        std::string osHint;
4587
0
        const CPLStringList aosVSIFSPrefixes(VSIFileManager::GetPrefixes());
4588
0
        for (const char *pszFSPrefix : aosVSIFSPrefixes)
4589
0
        {
4590
0
            auto poFS = VSIFileManager::GetHandler(pszFSPrefix);
4591
0
            if (poFS)
4592
0
            {
4593
0
                osHint = poFS->GetHintForPotentiallyRecognizedPath(pszFilename);
4594
0
                if (!osHint.empty())
4595
0
                {
4596
0
                    osHint = " Changing the filename to " + osHint +
4597
0
                             " may help it to be recognized.";
4598
0
                    break;
4599
0
                }
4600
0
            }
4601
0
        }
4602
4603
0
        if (nDriverCount == 0)
4604
0
        {
4605
0
            CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4606
0
        }
4607
0
        else if (poMissingPluginDriver)
4608
0
        {
4609
0
            std::string osMsg("`");
4610
0
            osMsg += pszFilename;
4611
0
            osMsg += "' not recognized as being in a supported file format. "
4612
0
                     "It could have been recognized by driver ";
4613
0
            osMsg += poMissingPluginDriver->GetDescription();
4614
0
            osMsg += ", but plugin ";
4615
0
            osMsg +=
4616
0
                GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4617
4618
0
            CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4619
0
        }
4620
        // Check to see if there was a filesystem error, and report it if so.
4621
        // If not, return a more generic error.
4622
0
        else if (!osHint.empty() && VSIGetLastErrorNo() == VSIE_FileError)
4623
0
        {
4624
0
            CPLError(CE_Failure, CPLE_FileIO, "%s.%s", VSIGetLastErrorMsg(),
4625
0
                     osHint.c_str());
4626
0
        }
4627
0
        else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4628
0
        {
4629
0
            if (oOpenInfo.bStatOK)
4630
0
            {
4631
0
                CPLError(CE_Failure, CPLE_OpenFailed,
4632
0
                         "`%s' not recognized as being in a supported file "
4633
0
                         "format.%s",
4634
0
                         pszFilename, osHint.c_str());
4635
0
            }
4636
0
            else
4637
0
            {
4638
                // If Stat failed and no VSI error was set, assume it is because
4639
                // the file did not exist on the filesystem.
4640
0
                CPLError(CE_Failure, CPLE_OpenFailed,
4641
0
                         "`%s' does not exist in the file system, "
4642
0
                         "and is not recognized as a supported dataset name.%s",
4643
0
                         pszFilename, osHint.c_str());
4644
0
            }
4645
0
        }
4646
0
    }
4647
4648
0
    return nullptr;
4649
0
}
4650
4651
/************************************************************************/
4652
/*                           GDALOpenShared()                           */
4653
/************************************************************************/
4654
4655
/**
4656
 * \brief Open a raster file as a GDALDataset.
4657
 *
4658
 * This function works the same as GDALOpen(), but allows the sharing of
4659
 * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4660
 *
4661
 * In particular, GDALOpenShared() will first consult its list of currently
4662
 * open and shared GDALDataset's, and if the GetDescription() name for one
4663
 * exactly matches the pszFilename passed to GDALOpenShared() it will be
4664
 * referenced and returned.
4665
 *
4666
 * If GDALOpenShared() is called on the same
4667
 * pszFilename from two different threads, a different GDALDataset object will
4668
 * be returned as it is not safe to use the same dataset from different threads,
4669
 * unless the user does explicitly use mutexes in its code.
4670
 *
4671
 * For drivers supporting the VSI virtual file API, it is possible to open a
4672
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4673
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4674
 * server (see VSIInstallCurlFileHandler())
4675
 *
4676
 * \sa GDALOpen()
4677
 * \sa GDALOpenEx()
4678
 *
4679
 * @param pszFilename the name of the file to access.  In the case of
4680
 * exotic drivers this may not refer to a physical file, but instead contain
4681
 * information for the driver on how to access a dataset.  It should be in
4682
 * UTF-8 encoding.
4683
 *
4684
 * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
4685
 * drivers support only read only access.
4686
 *
4687
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
4688
 * this handle can be cast to a GDALDataset *.
4689
 */
4690
4691
GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4692
                                        GDALAccess eAccess)
4693
0
{
4694
0
    VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4695
0
    return GDALOpenEx(pszFilename,
4696
0
                      GDAL_OF_RASTER |
4697
0
                          (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4698
0
                          GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4699
0
                      nullptr, nullptr, nullptr);
4700
0
}
4701
4702
/************************************************************************/
4703
/*                             GDALClose()                              */
4704
/************************************************************************/
4705
4706
/**
4707
 * \brief Close GDAL dataset.
4708
 *
4709
 * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4710
 * using the C++ "delete" operator, recovering all dataset related resources.
4711
 * For shared datasets (opened with GDALOpenShared()) the dataset is
4712
 * dereferenced, and closed only if the referenced count has dropped below 1.
4713
 *
4714
 * @param hDS The dataset to close, or nullptr.
4715
 * @return CE_None in case of success (return value since GDAL 3.7). On a
4716
 * shared dataset whose reference count is not dropped below 1, CE_None will
4717
 * be returned.
4718
 *
4719
 * @see GDALCloseEx()
4720
 */
4721
4722
CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4723
4724
0
{
4725
0
    return GDALCloseEx(hDS, nullptr, nullptr);
4726
0
}
4727
4728
/************************************************************************/
4729
/*                            GDALCloseEx()                             */
4730
/************************************************************************/
4731
4732
/**
4733
 * \brief Close GDAL dataset.
4734
 *
4735
 * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4736
 * using the C++ "delete" operator, recovering all dataset related resources.
4737
 * For shared datasets (opened with GDALOpenShared()) the dataset is
4738
 * dereferenced, and closed only if the referenced count has dropped below 1.
4739
 *
4740
 * This function may report progress if a progress
4741
 * callback if provided in the pfnProgress argument and if the dataset returns
4742
 * true for GDALDataset::GetCloseReportsProgress()
4743
4744
 * @param hDS The dataset to close, or nullptr
4745
 * @param pfnProgress Progress callback, or nullptr
4746
 * @param pProgressData User data of progress callback, or nullptr
4747
 *
4748
 * @return CE_None in case of success. On a
4749
 * shared dataset whose reference count is not dropped below 1, CE_None will
4750
 * be returned.
4751
 *
4752
 * @since GDAL 3.13
4753
 * @see GDALClose()
4754
 */
4755
4756
CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4757
                   void *pProgressData)
4758
0
{
4759
0
    if (!hDS)
4760
0
        return CE_None;
4761
4762
0
#ifdef OGRAPISPY_ENABLED
4763
0
    if (bOGRAPISpyEnabled)
4764
0
        OGRAPISpyPreClose(hDS);
4765
0
#endif
4766
4767
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4768
4769
0
    if (poDS->GetShared())
4770
0
    {
4771
        /* --------------------------------------------------------------------
4772
         */
4773
        /*      If this file is in the shared dataset list then dereference */
4774
        /*      it, and only delete/remote it if the reference count has */
4775
        /*      dropped to zero. */
4776
        /* --------------------------------------------------------------------
4777
         */
4778
0
        if (poDS->Dereference() > 0)
4779
0
            return CE_None;
4780
0
    }
4781
4782
0
    CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4783
0
    delete poDS;
4784
4785
0
#ifdef OGRAPISPY_ENABLED
4786
0
    if (bOGRAPISpyEnabled)
4787
0
        OGRAPISpyPostClose();
4788
0
#endif
4789
0
    return eErr;
4790
0
}
4791
4792
/************************************************************************/
4793
/*                        GDALDumpOpenDataset()                         */
4794
/************************************************************************/
4795
4796
static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4797
0
{
4798
0
    SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4799
0
    FILE *fp = static_cast<FILE *>(user_data);
4800
0
    GDALDataset *poDS = psStruct->poDS;
4801
4802
0
    const char *pszDriverName = poDS->GetDriver() == nullptr
4803
0
                                    ? "DriverIsNULL"
4804
0
                                    : poDS->GetDriver()->GetDescription();
4805
4806
0
    poDS->Reference();
4807
0
    CPL_IGNORE_RET_VAL(
4808
0
        VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4809
0
                   poDS->GetShared() ? 'S' : 'N', pszDriverName,
4810
0
                   static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4811
0
                   poDS->GetRasterYSize(), poDS->GetRasterCount(),
4812
0
                   poDS->GetDescription()));
4813
4814
0
    return TRUE;
4815
0
}
4816
4817
static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4818
0
{
4819
4820
    // Don't list shared datasets. They have already been listed by
4821
    // GDALDumpOpenSharedDatasetsForeach.
4822
0
    if (poDS->GetShared())
4823
0
        return TRUE;
4824
4825
0
    const char *pszDriverName = poDS->GetDriver() == nullptr
4826
0
                                    ? "DriverIsNULL"
4827
0
                                    : poDS->GetDriver()->GetDescription();
4828
4829
0
    poDS->Reference();
4830
0
    CPL_IGNORE_RET_VAL(
4831
0
        VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4832
0
                   poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4833
0
                   poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4834
0
                   poDS->GetRasterCount(), poDS->GetDescription()));
4835
4836
0
    return TRUE;
4837
0
}
4838
4839
/**
4840
 * \brief List open datasets.
4841
 *
4842
 * Dumps a list of all open datasets (shared or not) to the indicated
4843
 * text file (may be stdout or stderr).   This function is primarily intended
4844
 * to assist in debugging "dataset leaks" and reference counting issues.
4845
 * The information reported includes the dataset name, referenced count,
4846
 * shared status, driver name, size, and band count.
4847
 */
4848
4849
int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4850
4851
0
{
4852
0
    VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4853
4854
0
    CPLMutexHolderD(&hDLMutex);
4855
4856
0
    if (poAllDatasetMap == nullptr)
4857
0
        return 0;
4858
4859
0
    CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4860
4861
0
    for (const auto &oIter : *poAllDatasetMap)
4862
0
    {
4863
0
        GDALDumpOpenDatasetsForeach(oIter.first, fp);
4864
0
    }
4865
4866
0
    if (phSharedDatasetSet != nullptr)
4867
0
    {
4868
0
        CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4869
0
                          fp);
4870
0
    }
4871
0
    return static_cast<int>(poAllDatasetMap->size());
4872
0
}
4873
4874
/************************************************************************/
4875
/*                          BeginAsyncReader()                          */
4876
/************************************************************************/
4877
4878
/**
4879
 * \brief Sets up an asynchronous data request
4880
 *
4881
 * This method establish an asynchronous raster read request for the
4882
 * indicated window on the dataset into the indicated buffer.  The parameters
4883
 * for windowing, buffer size, buffer type and buffer organization are similar
4884
 * to those for GDALDataset::RasterIO(); however, this call only launches
4885
 * the request and filling the buffer is accomplished via calls to
4886
 * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4887
 *
4888
 * Once all processing for the created session is complete, or if no further
4889
 * refinement of the request is required, the GDALAsyncReader object should
4890
 * be destroyed with the GDALDataset::EndAsyncReader() method.
4891
 *
4892
 * Note that the data buffer (pData) will potentially continue to be
4893
 * updated as long as the session lives, but it is not deallocated when
4894
 * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
4895
 * should be deallocated by the application at that point.
4896
 *
4897
 * Additional information on asynchronous IO in GDAL may be found at:
4898
 *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4899
 *
4900
 * This method is the same as the C GDALBeginAsyncReader() function.
4901
 *
4902
 * @param nXOff The pixel offset to the top left corner of the region
4903
 * of the band to be accessed.  This would be zero to start from the left side.
4904
 *
4905
 * @param nYOff The line offset to the top left corner of the region
4906
 * of the band to be accessed.  This would be zero to start from the top.
4907
 *
4908
 * @param nXSize The width of the region of the band to be accessed in pixels.
4909
 *
4910
 * @param nYSize The height of the region of the band to be accessed in lines.
4911
 *
4912
 * @param pBuf The buffer into which the data should be read. This buffer must
4913
 * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4914
 * It is organized in left to right,top to bottom pixel order.  Spacing is
4915
 * controlled by the nPixelSpace, and nLineSpace parameters.
4916
 *
4917
 * @param nBufXSize the width of the buffer image into which the desired region
4918
 * is to be read, or from which it is to be written.
4919
 *
4920
 * @param nBufYSize the height of the buffer image into which the desired
4921
 * region is to be read, or from which it is to be written.
4922
 *
4923
 * @param eBufType the type of the pixel values in the pData data buffer.  The
4924
 * pixel values will automatically be translated to/from the GDALRasterBand
4925
 * data type as needed.
4926
 *
4927
 * @param nBandCount the number of bands being read or written.
4928
 *
4929
 * @param panBandMap the list of nBandCount band numbers being read/written.
4930
 * Note band numbers are 1 based.   This may be NULL to select the first
4931
 * nBandCount bands.
4932
 *
4933
 * @param nPixelSpace The byte offset from the start of one pixel value in
4934
 * pData to the start of the next pixel value within a scanline.  If defaulted
4935
 * (0) the size of the datatype eBufType is used.
4936
 *
4937
 * @param nLineSpace The byte offset from the start of one scanline in
4938
 * pData to the start of the next.  If defaulted the size of the datatype
4939
 * eBufType * nBufXSize is used.
4940
 *
4941
 * @param nBandSpace the byte offset from the start of one bands data to the
4942
 * start of the next.  If defaulted (zero) the value will be
4943
 * nLineSpace * nBufYSize implying band sequential organization
4944
 * of the data buffer.
4945
 *
4946
 * @param papszOptions Driver specific control options in a string list or NULL.
4947
 * Consult driver documentation for options supported.
4948
 *
4949
 * @return The GDALAsyncReader object representing the request.
4950
 */
4951
4952
GDALAsyncReader *GDALDataset::BeginAsyncReader(
4953
    int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4954
    int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4955
    int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4956
0
{
4957
    // See gdaldefaultasync.cpp
4958
4959
0
    return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4960
0
                                     nBufXSize, nBufYSize, eBufType, nBandCount,
4961
0
                                     panBandMap, nPixelSpace, nLineSpace,
4962
0
                                     nBandSpace, papszOptions);
4963
0
}
4964
4965
/************************************************************************/
4966
/*                        GDALBeginAsyncReader()                        */
4967
/************************************************************************/
4968
4969
/**
4970
 * \brief Sets up an asynchronous data request
4971
 *
4972
 * This method establish an asynchronous raster read request for the
4973
 * indicated window on the dataset into the indicated buffer.  The parameters
4974
 * for windowing, buffer size, buffer type and buffer organization are similar
4975
 * to those for GDALDataset::RasterIO(); however, this call only launches
4976
 * the request and filling the buffer is accomplished via calls to
4977
 * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4978
 *
4979
 * Once all processing for the created session is complete, or if no further
4980
 * refinement of the request is required, the GDALAsyncReader object should
4981
 * be destroyed with the GDALDataset::EndAsyncReader() method.
4982
 *
4983
 * Note that the data buffer (pData) will potentially continue to be
4984
 * updated as long as the session lives, but it is not deallocated when
4985
 * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
4986
 * should be deallocated by the application at that point.
4987
 *
4988
 * Additional information on asynchronous IO in GDAL may be found at:
4989
 *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4990
 *
4991
 * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4992
 *
4993
 * @param hDS handle to the dataset object.
4994
 *
4995
 * @param nXOff The pixel offset to the top left corner of the region
4996
 * of the band to be accessed.  This would be zero to start from the left side.
4997
 *
4998
 * @param nYOff The line offset to the top left corner of the region
4999
 * of the band to be accessed.  This would be zero to start from the top.
5000
 *
5001
 * @param nXSize The width of the region of the band to be accessed in pixels.
5002
 *
5003
 * @param nYSize The height of the region of the band to be accessed in lines.
5004
 *
5005
 * @param pBuf The buffer into which the data should be read. This buffer must
5006
 * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
5007
 * It is organized in left to right,top to bottom pixel order.  Spacing is
5008
 * controlled by the nPixelSpace, and nLineSpace parameters.
5009
 *
5010
 * @param nBufXSize the width of the buffer image into which the desired region
5011
 * is to be read, or from which it is to be written.
5012
 *
5013
 * @param nBufYSize the height of the buffer image into which the desired
5014
 * region is to be read, or from which it is to be written.
5015
 *
5016
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5017
 * pixel values will automatically be translated to/from the GDALRasterBand
5018
 * data type as needed.
5019
 *
5020
 * @param nBandCount the number of bands being read or written.
5021
 *
5022
 * @param panBandMap the list of nBandCount band numbers being read/written.
5023
 * Note band numbers are 1 based.   This may be NULL to select the first
5024
 * nBandCount bands.
5025
 *
5026
 * @param nPixelSpace The byte offset from the start of one pixel value in
5027
 * pData to the start of the next pixel value within a scanline.  If defaulted
5028
 * (0) the size of the datatype eBufType is used.
5029
 *
5030
 * @param nLineSpace The byte offset from the start of one scanline in
5031
 * pData to the start of the next.  If defaulted the size of the datatype
5032
 * eBufType * nBufXSize is used.
5033
 *
5034
 * @param nBandSpace the byte offset from the start of one bands data to the
5035
 * start of the next.  If defaulted (zero) the value will be
5036
 * nLineSpace * nBufYSize implying band sequential organization
5037
 * of the data buffer.
5038
 *
5039
 * @param papszOptions Driver specific control options in a string list or NULL.
5040
 * Consult driver documentation for options supported.
5041
 *
5042
 * @return handle representing the request.
5043
 */
5044
5045
GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5046
    GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5047
    int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5048
    int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5049
    CSLConstList papszOptions)
5050
5051
0
{
5052
0
    VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5053
0
    return static_cast<GDALAsyncReaderH>(
5054
0
        GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5055
0
            nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5056
0
            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5057
0
            const_cast<char **>(papszOptions)));
5058
0
}
5059
5060
/************************************************************************/
5061
/*                           EndAsyncReader()                           */
5062
/************************************************************************/
5063
5064
/**
5065
 * End asynchronous request.
5066
 *
5067
 * This method destroys an asynchronous io request and recovers all
5068
 * resources associated with it.
5069
 *
5070
 * This method is the same as the C function GDALEndAsyncReader().
5071
 *
5072
 * @param poARIO pointer to a GDALAsyncReader
5073
 */
5074
5075
void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5076
0
{
5077
0
    delete poARIO;
5078
0
}
5079
5080
/************************************************************************/
5081
/*                         GDALEndAsyncReader()                         */
5082
/************************************************************************/
5083
5084
/**
5085
 * End asynchronous request.
5086
 *
5087
 * This method destroys an asynchronous io request and recovers all
5088
 * resources associated with it.
5089
 *
5090
 * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5091
 *
5092
 * @param hDS handle to the dataset object.
5093
 * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5094
 */
5095
5096
void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5097
                                    GDALAsyncReaderH hAsyncReaderH)
5098
0
{
5099
0
    VALIDATE_POINTER0(hDS, "GDALDataset");
5100
0
    VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5101
0
    GDALDataset::FromHandle(hDS)->EndAsyncReader(
5102
0
        static_cast<GDALAsyncReader *>(hAsyncReaderH));
5103
0
}
5104
5105
/************************************************************************/
5106
/*                       CloseDependentDatasets()                       */
5107
/************************************************************************/
5108
5109
/**
5110
 * Drop references to any other datasets referenced by this dataset.
5111
 *
5112
 * This method should release any reference to other datasets (e.g. a VRT
5113
 * dataset to its sources), but not close the current dataset itself.
5114
 *
5115
 * If at least, one reference to a dependent dataset has been dropped,
5116
 * this method should return TRUE. Otherwise it *should* return FALSE.
5117
 * (Failure to return the proper value might result in infinite loop)
5118
 *
5119
 * This method can be called several times on a given dataset. After
5120
 * the first time, it should not do anything and return FALSE.
5121
 *
5122
 * The driver implementation may choose to destroy its raster bands,
5123
 * so be careful not to call any method on the raster bands afterwards.
5124
 *
5125
 * Basically the only safe action you can do after calling
5126
 * CloseDependentDatasets() is to call the destructor.
5127
 *
5128
 * Note: the only legitimate caller of CloseDependentDatasets() is
5129
 * GDALDriverManager::~GDALDriverManager()
5130
 *
5131
 * @return TRUE if at least one reference to another dataset has been dropped.
5132
 */
5133
int GDALDataset::CloseDependentDatasets()
5134
0
{
5135
0
    return oOvManager.CloseDependentDatasets();
5136
0
}
5137
5138
/************************************************************************/
5139
/*                            ReportError()                             */
5140
/************************************************************************/
5141
5142
#ifndef DOXYGEN_XML
5143
/**
5144
 * \brief Emits an error related to a dataset.
5145
 *
5146
 * This function is a wrapper for regular CPLError(). The only difference
5147
 * with CPLError() is that it prepends the error message with the dataset
5148
 * name.
5149
 *
5150
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5151
 * @param err_no the error number (CPLE_*) from cpl_error.h.
5152
 * @param fmt a printf() style format string.  Any additional arguments
5153
 * will be treated as arguments to fill in this format in a manner
5154
 * similar to printf().
5155
 *
5156
 */
5157
5158
void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5159
                              const char *fmt, ...) const
5160
0
{
5161
0
    va_list args;
5162
0
    va_start(args, fmt);
5163
0
    ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5164
0
    va_end(args);
5165
0
}
5166
5167
/**
5168
 * \brief Emits an error related to a dataset (static method)
5169
 *
5170
 * This function is a wrapper for regular CPLError(). The only difference
5171
 * with CPLError() is that it prepends the error message with the dataset
5172
 * name.
5173
 *
5174
 * @param pszDSName dataset name.
5175
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5176
 * @param err_no the error number (CPLE_*) from cpl_error.h.
5177
 * @param fmt a printf() style format string.  Any additional arguments
5178
 * will be treated as arguments to fill in this format in a manner
5179
 * similar to printf().
5180
 *
5181
 * @since GDAL 3.2.0
5182
 */
5183
5184
void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5185
                              CPLErrorNum err_no, const char *fmt, ...)
5186
0
{
5187
0
    va_list args;
5188
0
    va_start(args, fmt);
5189
0
    ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5190
0
    va_end(args);
5191
0
}
5192
5193
void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5194
                               CPLErrorNum err_no, const char *fmt,
5195
                               va_list args)
5196
0
{
5197
0
    pszDSName = CPLGetFilename(pszDSName);
5198
0
    if (pszDSName[0] != '\0')
5199
0
    {
5200
0
        CPLError(eErrClass, err_no, "%s",
5201
0
                 std::string(pszDSName)
5202
0
                     .append(": ")
5203
0
                     .append(CPLString().vPrintf(fmt, args))
5204
0
                     .c_str());
5205
0
    }
5206
0
    else
5207
0
    {
5208
0
        CPLErrorV(eErrClass, err_no, fmt, args);
5209
0
    }
5210
0
}
5211
#endif
5212
5213
/************************************************************************/
5214
/*                            GetMetadata()                             */
5215
/************************************************************************/
5216
CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5217
0
{
5218
#ifndef WITHOUT_DERIVED
5219
    if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5220
    {
5221
        oDerivedMetadataList.Clear();
5222
5223
        // First condition: at least one raster band.
5224
        if (GetRasterCount() > 0)
5225
        {
5226
            // Check if there is at least one complex band.
5227
            bool hasAComplexBand = false;
5228
5229
            for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5230
            {
5231
                if (GDALDataTypeIsComplex(
5232
                        GetRasterBand(rasterId)->GetRasterDataType()))
5233
                {
5234
                    hasAComplexBand = true;
5235
                    break;
5236
                }
5237
            }
5238
5239
            unsigned int nbSupportedDerivedDS = 0;
5240
            const DerivedDatasetDescription *poDDSDesc =
5241
                GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5242
5243
            int nNumDataset = 1;
5244
            for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5245
                 ++derivedId)
5246
            {
5247
                if (hasAComplexBand ||
5248
                    CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5249
                        "complex")
5250
                {
5251
                    oDerivedMetadataList.SetNameValue(
5252
                        CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5253
                        CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5254
                                   poDDSDesc[derivedId].pszDatasetName,
5255
                                   GetDescription()));
5256
5257
                    CPLString osDesc(
5258
                        CPLSPrintf("%s from %s",
5259
                                   poDDSDesc[derivedId].pszDatasetDescription,
5260
                                   GetDescription()));
5261
                    oDerivedMetadataList.SetNameValue(
5262
                        CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5263
                        osDesc.c_str());
5264
5265
                    nNumDataset++;
5266
                }
5267
            }
5268
        }
5269
        return oDerivedMetadataList.List();
5270
    }
5271
#endif
5272
5273
0
    return GDALMajorObject::GetMetadata(pszDomain);
5274
0
}
5275
5276
// clang-format off
5277
5278
/**
5279
 * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5280
 * \brief Set metadata.
5281
 *
5282
 * CAUTION: depending on the format, older values of the updated information
5283
 * might still be found in the file in a "ghost" state, even if no longer
5284
 * accessible through the GDAL API. This is for example the case of the GTiff
5285
 * format (this is not a exhaustive list)
5286
 *
5287
 * The C function GDALSetMetadata() does the same thing as this method.
5288
 *
5289
 * @param papszMetadata the metadata in name=value string list format to
5290
 * apply.
5291
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
5292
 * domain.
5293
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5294
 * metadata has been accepted, but is likely not maintained persistently
5295
 * by the underlying object between sessions.
5296
 */
5297
5298
/**
5299
 * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5300
 * \brief Set single metadata item.
5301
 *
5302
 * CAUTION: depending on the format, older values of the updated information
5303
 * might still be found in the file in a "ghost" state, even if no longer
5304
 * accessible through the GDAL API. This is for example the case of the GTiff
5305
 * format (this is not a exhaustive list)
5306
 *
5307
 * The C function GDALSetMetadataItem() does the same thing as this method.
5308
 *
5309
 * @param pszName the key for the metadata item to fetch.
5310
 * @param pszValue the value to assign to the key.
5311
 * @param pszDomain the domain to set within, use NULL for the default domain.
5312
 *
5313
 * @return CE_None on success, or an error code on failure.
5314
 */
5315
5316
// clang-format on
5317
5318
/************************************************************************/
5319
/*                       GetMetadataDomainList()                        */
5320
/************************************************************************/
5321
5322
char **GDALDataset::GetMetadataDomainList()
5323
0
{
5324
0
    char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5325
5326
    // Ensure that we do not duplicate DERIVED domain.
5327
0
    if (GetRasterCount() > 0 &&
5328
0
        CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5329
0
    {
5330
0
        currentDomainList =
5331
0
            CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5332
0
    }
5333
0
    return currentDomainList;
5334
0
}
5335
5336
/************************************************************************/
5337
/*                           GetDriverName()                            */
5338
/************************************************************************/
5339
5340
/** Return driver name.
5341
 * @return driver name.
5342
 */
5343
const char *GDALDataset::GetDriverName() const
5344
0
{
5345
0
    if (poDriver)
5346
0
        return poDriver->GetDescription();
5347
0
    return "";
5348
0
}
5349
5350
/************************************************************************/
5351
/*                    GDALDatasetReleaseResultSet()                     */
5352
/************************************************************************/
5353
5354
/**
5355
 \brief Release results of ExecuteSQL().
5356
5357
 This function should only be used to deallocate OGRLayers resulting from
5358
 an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
5359
 results set before destroying the GDALDataset may cause errors.
5360
5361
 This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5362
5363
5364
 @param hDS the dataset handle.
5365
 @param hLayer the result of a previous ExecuteSQL() call.
5366
5367
*/
5368
void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5369
5370
0
{
5371
0
    VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5372
5373
0
#ifdef OGRAPISPY_ENABLED
5374
0
    if (bOGRAPISpyEnabled)
5375
0
        OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5376
0
#endif
5377
5378
0
    GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5379
0
        OGRLayer::FromHandle(hLayer));
5380
0
}
5381
5382
/************************************************************************/
5383
/*                      GDALDatasetGetLayerCount()                      */
5384
/************************************************************************/
5385
5386
/**
5387
 \brief Get the number of layers in this dataset.
5388
5389
 This function is the same as the C++ method GDALDataset::GetLayerCount()
5390
5391
5392
 @param hDS the dataset handle.
5393
 @return layer count.
5394
*/
5395
5396
int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5397
5398
0
{
5399
0
    VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5400
5401
0
#ifdef OGRAPISPY_ENABLED
5402
0
    if (bOGRAPISpyEnabled)
5403
0
        OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5404
0
#endif
5405
5406
0
    return GDALDataset::FromHandle(hDS)->GetLayerCount();
5407
0
}
5408
5409
/************************************************************************/
5410
/*                        GDALDatasetGetLayer()                         */
5411
/************************************************************************/
5412
5413
/**
5414
 \brief Fetch a layer by index.
5415
5416
 The returned layer remains owned by the
5417
 GDALDataset and should not be deleted by the application.
5418
5419
 This function is the same as the C++ method GDALDataset::GetLayer()
5420
5421
5422
 @param hDS the dataset handle.
5423
 @param iLayer a layer number between 0 and GetLayerCount()-1.
5424
5425
 @return the layer, or NULL if iLayer is out of range or an error occurs.
5426
*/
5427
5428
OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5429
5430
0
{
5431
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5432
5433
0
    OGRLayerH hLayer =
5434
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5435
5436
0
#ifdef OGRAPISPY_ENABLED
5437
0
    if (bOGRAPISpyEnabled)
5438
0
        OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5439
0
#endif
5440
5441
0
    return hLayer;
5442
0
}
5443
5444
/************************************************************************/
5445
/*                     GDALDatasetGetLayerByName()                      */
5446
/************************************************************************/
5447
5448
/**
5449
 \brief Fetch a layer by name.
5450
5451
 The returned layer remains owned by the
5452
 GDALDataset and should not be deleted by the application.
5453
5454
 This function is the same as the C++ method GDALDataset::GetLayerByName()
5455
5456
5457
 @param hDS the dataset handle.
5458
 @param pszName the layer name of the layer to fetch.
5459
5460
 @return the layer, or NULL if Layer is not found or an error occurs.
5461
*/
5462
5463
OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5464
5465
0
{
5466
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5467
5468
0
    OGRLayerH hLayer = OGRLayer::ToHandle(
5469
0
        GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5470
5471
0
#ifdef OGRAPISPY_ENABLED
5472
0
    if (bOGRAPISpyEnabled)
5473
0
        OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5474
0
#endif
5475
5476
0
    return hLayer;
5477
0
}
5478
5479
/************************************************************************/
5480
/*                     GDALDatasetIsLayerPrivate()                      */
5481
/************************************************************************/
5482
5483
/**
5484
 \brief Returns true if the layer at the specified index is deemed a private or
5485
 system table, or an internal detail only.
5486
5487
 This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5488
5489
 @since GDAL 3.4
5490
5491
 @param hDS the dataset handle.
5492
 @param iLayer a layer number between 0 and GetLayerCount()-1.
5493
5494
 @return true if the layer is a private or system table.
5495
*/
5496
5497
int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5498
5499
0
{
5500
0
    VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5501
5502
0
    const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5503
5504
0
    return res ? 1 : 0;
5505
0
}
5506
5507
/************************************************************************/
5508
/*                           GetLayerIndex()                            */
5509
/************************************************************************/
5510
5511
/**
5512
 \brief Returns the index of the layer specified by name.
5513
5514
 @since GDAL 3.12
5515
5516
 @param pszName layer name (not NULL)
5517
5518
 @return an index >= 0, or -1 if not found.
5519
*/
5520
5521
int GDALDataset::GetLayerIndex(const char *pszName) const
5522
0
{
5523
0
    const int nLayerCount = GetLayerCount();
5524
0
    int iMatch = -1;
5525
0
    for (int i = 0; i < nLayerCount; ++i)
5526
0
    {
5527
0
        if (const auto poLayer = GetLayer(i))
5528
0
        {
5529
0
            const char *pszLayerName = poLayer->GetDescription();
5530
0
            if (strcmp(pszName, pszLayerName) == 0)
5531
0
            {
5532
0
                iMatch = i;
5533
0
                break;
5534
0
            }
5535
0
            else if (EQUAL(pszName, pszLayerName))
5536
0
            {
5537
0
                iMatch = i;
5538
0
            }
5539
0
        }
5540
0
    }
5541
0
    return iMatch;
5542
0
}
5543
5544
/************************************************************************/
5545
/*                       GDALDatasetDeleteLayer()                       */
5546
/************************************************************************/
5547
5548
/**
5549
 \brief Delete the indicated layer from the datasource.
5550
5551
 If this function is supported
5552
 the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5553
5554
 This method is the same as the C++ method GDALDataset::DeleteLayer().
5555
5556
5557
 @param hDS the dataset handle.
5558
 @param iLayer the index of the layer to delete.
5559
5560
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5561
 layers is not supported for this datasource.
5562
5563
*/
5564
OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5565
5566
0
{
5567
0
    VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5568
5569
0
#ifdef OGRAPISPY_ENABLED
5570
0
    if (bOGRAPISpyEnabled)
5571
0
        OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5572
0
#endif
5573
5574
0
    return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5575
0
}
5576
5577
/************************************************************************/
5578
/*                            CreateLayer()                             */
5579
/************************************************************************/
5580
5581
/**
5582
\brief This method attempts to create a new layer on the dataset with the
5583
indicated name, coordinate system, geometry type.
5584
5585
The papszOptions argument
5586
can be used to control driver specific creation options.  These options are
5587
normally documented in the format specific documentation.
5588
That function will try to validate the creation option list passed to the
5589
driver with the GDALValidateCreationOptions() method. This check can be
5590
disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5591
to NO.
5592
5593
Drivers should extend the ICreateLayer() method and not
5594
CreateLayer(). CreateLayer() adds validation of layer creation options, before
5595
delegating the actual work to ICreateLayer().
5596
5597
This method is the same as the C function GDALDatasetCreateLayer() and the
5598
deprecated OGR_DS_CreateLayer().
5599
5600
Example:
5601
5602
\code{.cpp}
5603
#include "gdal.h"
5604
#include "cpl_string.h"
5605
5606
...
5607
5608
        OGRLayer *poLayer;
5609
        char     **papszOptions;
5610
5611
        if( !poDS->TestCapability( ODsCCreateLayer ) )
5612
        {
5613
        ...
5614
        }
5615
5616
        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5617
        poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5618
                                     papszOptions );
5619
        CSLDestroy( papszOptions );
5620
5621
        if( poLayer == NULL )
5622
        {
5623
            ...
5624
        }
5625
\endcode
5626
5627
@param pszName the name for the new layer.  This should ideally not
5628
match any existing layer on the datasource.
5629
@param poSpatialRef the coordinate system to use for the new layer, or NULL if
5630
no coordinate system is available.
5631
@param eGType the geometry type for the layer.  Use wkbUnknown if there
5632
are no constraints on the types geometry to be written.
5633
@param papszOptions a StringList of name=value options.  Options are driver
5634
specific.
5635
5636
@return NULL is returned on failure, or a new OGRLayer handle on success.
5637
5638
*/
5639
5640
OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5641
                                   const OGRSpatialReference *poSpatialRef,
5642
                                   OGRwkbGeometryType eGType,
5643
                                   CSLConstList papszOptions)
5644
5645
0
{
5646
0
    if (eGType == wkbNone)
5647
0
    {
5648
0
        return CreateLayer(pszName, nullptr, papszOptions);
5649
0
    }
5650
0
    else
5651
0
    {
5652
0
        OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5653
0
        oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5654
0
        return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5655
0
    }
5656
0
}
5657
5658
/**
5659
\brief This method attempts to create a new layer on the dataset with the
5660
indicated name and geometry field definition.
5661
5662
When poGeomFieldDefn is not null, most drivers should honor
5663
poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5664
Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5665
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5666
poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5667
very few currently.
5668
5669
Note that even if a geometry coordinate precision is set and a driver honors the
5670
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5671
OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5672
with the coordinate precision. That is they are assumed to be valid once their
5673
coordinates are rounded to it. If it might not be the case, the user may set
5674
the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5675
or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5676
the passed geometries.
5677
5678
The papszOptions argument
5679
can be used to control driver specific creation options. These options are
5680
normally documented in the format specific documentation.
5681
This function will try to validate the creation option list passed to the
5682
driver with the GDALValidateCreationOptions() method. This check can be
5683
disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5684
to NO.
5685
5686
Drivers should extend the ICreateLayer() method and not
5687
CreateLayer(). CreateLayer() adds validation of layer creation options, before
5688
delegating the actual work to ICreateLayer().
5689
5690
This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5691
5692
@param pszName the name for the new layer.  This should ideally not
5693
match any existing layer on the datasource.
5694
@param poGeomFieldDefn the geometry field definition to use for the new layer,
5695
or NULL if there is no geometry field.
5696
@param papszOptions a StringList of name=value options.  Options are driver
5697
specific.
5698
5699
@return NULL is returned on failure, or a new OGRLayer handle on success.
5700
@since 3.9
5701
5702
*/
5703
5704
OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5705
                                   const OGRGeomFieldDefn *poGeomFieldDefn,
5706
                                   CSLConstList papszOptions)
5707
5708
0
{
5709
0
    if (CPLTestBool(
5710
0
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5711
0
    {
5712
0
        ValidateLayerCreationOptions(papszOptions);
5713
0
    }
5714
5715
0
    OGRLayer *poLayer;
5716
0
    if (poGeomFieldDefn)
5717
0
    {
5718
0
        OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5719
0
        if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5720
0
            !TestCapability(ODsCCurveGeometries))
5721
0
        {
5722
0
            oGeomFieldDefn.SetType(
5723
0
                OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5724
0
        }
5725
5726
0
        poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5727
0
    }
5728
0
    else
5729
0
    {
5730
0
        poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5731
0
    }
5732
0
#ifdef DEBUG
5733
0
    if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5734
0
        !poLayer->TestCapability(OLCCurveGeometries))
5735
0
    {
5736
0
        CPLError(CE_Warning, CPLE_AppDefined,
5737
0
                 "Inconsistent driver: Layer geometry type is non-linear, but "
5738
0
                 "TestCapability(OLCCurveGeometries) returns FALSE.");
5739
0
    }
5740
0
#endif
5741
5742
0
    return poLayer;
5743
0
}
5744
5745
//! @cond Doxygen_Suppress
5746
5747
// Technical override to avoid ambiguous choice between the old and new
5748
// new CreateLayer() signatures.
5749
OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5750
0
{
5751
0
    OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5752
0
    return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5753
0
}
5754
5755
// Technical override to avoid ambiguous choice between the old and new
5756
// new CreateLayer() signatures.
5757
OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5758
0
{
5759
0
    OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5760
0
    return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5761
0
}
5762
5763
//!@endcond
5764
5765
/************************************************************************/
5766
/*                       GDALDatasetCreateLayer()                       */
5767
/************************************************************************/
5768
5769
/**
5770
\brief This function attempts to create a new layer on the dataset with the
5771
indicated name, coordinate system, geometry type.
5772
5773
The papszOptions argument can be used to control driver specific creation
5774
options.  These options are normally documented in the format specific
5775
documentation.
5776
5777
This method is the same as the C++ method GDALDataset::CreateLayer().
5778
5779
Example:
5780
5781
\code{.c}
5782
#include "gdal.h"
5783
#include "cpl_string.h"
5784
5785
...
5786
5787
        OGRLayerH  hLayer;
5788
        char     **papszOptions;
5789
5790
        if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5791
        {
5792
        ...
5793
        }
5794
5795
        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5796
        hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5797
                                         papszOptions );
5798
        CSLDestroy( papszOptions );
5799
5800
        if( hLayer == NULL )
5801
        {
5802
            ...
5803
        }
5804
\endcode
5805
5806
5807
@param hDS the dataset handle
5808
@param pszName the name for the new layer.  This should ideally not
5809
match any existing layer on the datasource.
5810
@param hSpatialRef the coordinate system to use for the new layer, or NULL if
5811
no coordinate system is available.
5812
@param eGType the geometry type for the layer.  Use wkbUnknown if there
5813
are no constraints on the types geometry to be written.
5814
@param papszOptions a StringList of name=value options.  Options are driver
5815
specific.
5816
5817
@return NULL is returned on failure, or a new OGRLayer handle on success.
5818
5819
*/
5820
5821
OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5822
                                 OGRSpatialReferenceH hSpatialRef,
5823
                                 OGRwkbGeometryType eGType,
5824
                                 CSLConstList papszOptions)
5825
5826
0
{
5827
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5828
5829
0
    if (pszName == nullptr)
5830
0
    {
5831
0
        CPLError(CE_Failure, CPLE_ObjectNull,
5832
0
                 "Name was NULL in GDALDatasetCreateLayer");
5833
0
        return nullptr;
5834
0
    }
5835
5836
0
    OGRLayerH hLayer =
5837
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5838
0
            pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5839
0
            const_cast<char **>(papszOptions)));
5840
5841
0
#ifdef OGRAPISPY_ENABLED
5842
0
    if (bOGRAPISpyEnabled)
5843
0
        OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5844
0
                                 const_cast<char **>(papszOptions), hLayer);
5845
0
#endif
5846
5847
0
    return hLayer;
5848
0
}
5849
5850
/************************************************************************/
5851
/*              GDALDatasetCreateLayerFromGeomFieldDefn()               */
5852
/************************************************************************/
5853
5854
/**
5855
\brief This function attempts to create a new layer on the dataset with the
5856
indicated name and geometry field.
5857
5858
When poGeomFieldDefn is not null, most drivers should honor
5859
poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5860
Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5861
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5862
poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5863
very few currently.
5864
5865
Note that even if a geometry coordinate precision is set and a driver honors the
5866
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5867
OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5868
with the coordinate precision. That is they are assumed to be valid once their
5869
coordinates are rounded to it. If it might not be the case, the user may set
5870
the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5871
or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5872
the passed geometries.
5873
5874
The papszOptions argument can be used to control driver specific creation
5875
options.  These options are normally documented in the format specific
5876
documentation.
5877
5878
This method is the same as the C++ method GDALDataset::CreateLayer().
5879
5880
@param hDS the dataset handle
5881
@param pszName the name for the new layer.  This should ideally not
5882
match any existing layer on the datasource.
5883
@param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5884
a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5885
for drivers supporting that interface).
5886
@param papszOptions a StringList of name=value options.  Options are driver
5887
specific.
5888
5889
@return NULL is returned on failure, or a new OGRLayer handle on success.
5890
5891
@since GDAL 3.9
5892
5893
*/
5894
5895
OGRLayerH
5896
GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5897
                                        OGRGeomFieldDefnH hGeomFieldDefn,
5898
                                        CSLConstList papszOptions)
5899
5900
0
{
5901
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5902
5903
0
    if (!pszName)
5904
0
    {
5905
0
        CPLError(CE_Failure, CPLE_ObjectNull,
5906
0
                 "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5907
0
        return nullptr;
5908
0
    }
5909
5910
0
    OGRLayerH hLayer =
5911
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5912
0
            pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5913
0
            papszOptions));
5914
0
    return hLayer;
5915
0
}
5916
5917
/************************************************************************/
5918
/*                        GDALDatasetCopyLayer()                        */
5919
/************************************************************************/
5920
5921
/**
5922
 \brief Duplicate an existing layer.
5923
5924
 This function creates a new layer, duplicate the field definitions of the
5925
 source layer and then duplicate each features of the source layer.
5926
 The papszOptions argument
5927
 can be used to control driver specific creation options.  These options are
5928
 normally documented in the format specific documentation.
5929
 The source layer may come from another dataset.
5930
5931
 This method is the same as the C++ method GDALDataset::CopyLayer()
5932
5933
5934
 @param hDS the dataset handle.
5935
 @param hSrcLayer source layer.
5936
 @param pszNewName the name of the layer to create.
5937
 @param papszOptions a StringList of name=value options.  Options are driver
5938
                     specific.
5939
5940
 @return a handle to the layer, or NULL if an error occurs.
5941
*/
5942
OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5943
                               const char *pszNewName,
5944
                               CSLConstList papszOptions)
5945
5946
0
{
5947
0
    VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5948
0
    VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5949
0
    VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5950
5951
0
    return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5952
0
        OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5953
0
}
5954
5955
/************************************************************************/
5956
/*                       GDALDatasetExecuteSQL()                        */
5957
/************************************************************************/
5958
5959
/**
5960
 \brief Execute an SQL statement against the data store.
5961
5962
 The result of an SQL query is either NULL for statements that are in error,
5963
 or that have no results set, or an OGRLayer pointer representing a results
5964
 set from the query.  Note that this OGRLayer is in addition to the layers
5965
 in the data store and must be destroyed with
5966
 ReleaseResultSet() before the dataset is closed
5967
 (destroyed).
5968
5969
 This method is the same as the C++ method GDALDataset::ExecuteSQL()
5970
5971
 For more information on the SQL dialect supported internally by OGR
5972
 review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5973
 document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5974
 to the underlying RDBMS.
5975
5976
 Starting with OGR 1.10, the <a
5977
 href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5978
 also be used.
5979
5980
5981
 @param hDS the dataset handle.
5982
 @param pszStatement the SQL statement to execute.
5983
 @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5984
5985
 @param pszDialect allows control of the statement dialect. If set to NULL, the
5986
 OGR SQL engine will be used, except for RDBMS drivers that will use their
5987
 dedicated SQL engine, unless OGRSQL is explicitly passed as the
5988
 dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5989
5990
 @return an OGRLayer containing the results of the query.  Deallocate with
5991
 GDALDatasetReleaseResultSet().
5992
5993
*/
5994
5995
OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5996
                                OGRGeometryH hSpatialFilter,
5997
                                const char *pszDialect)
5998
5999
0
{
6000
0
    VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
6001
6002
0
    OGRLayerH hLayer =
6003
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
6004
0
            pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
6005
6006
0
#ifdef OGRAPISPY_ENABLED
6007
0
    if (bOGRAPISpyEnabled)
6008
0
        OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
6009
0
                                hLayer);
6010
0
#endif
6011
6012
0
    return hLayer;
6013
0
}
6014
6015
/************************************************************************/
6016
/*                        GDALDatasetAbortSQL()                         */
6017
/************************************************************************/
6018
6019
/**
6020
 \brief Abort any SQL statement running in the data store.
6021
6022
 This function can be safely called from any thread (pending that the dataset
6023
 object is still alive). Driver implementations will make sure that it can be
6024
 called in a thread-safe way.
6025
6026
 This might not be implemented by all drivers. At time of writing, only SQLite,
6027
 GPKG and PG drivers implement it
6028
6029
 This method is the same as the C++ method GDALDataset::AbortSQL()
6030
6031
 @since GDAL 3.2.0
6032
6033
 @param hDS the dataset handle.
6034
6035
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6036
 is not supported for this datasource. .
6037
6038
*/
6039
6040
OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6041
6042
0
{
6043
0
    VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6044
0
    return GDALDataset::FromHandle(hDS)->AbortSQL();
6045
0
}
6046
6047
/************************************************************************/
6048
/*                      GDALDatasetGetStyleTable()                      */
6049
/************************************************************************/
6050
6051
/**
6052
 \brief Returns dataset style table.
6053
6054
 This function is the same as the C++ method GDALDataset::GetStyleTable()
6055
6056
6057
 @param hDS the dataset handle
6058
 @return handle to a style table which should not be modified or freed by the
6059
 caller.
6060
*/
6061
6062
OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6063
6064
0
{
6065
0
    VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6066
6067
0
    return reinterpret_cast<OGRStyleTableH>(
6068
0
        GDALDataset::FromHandle(hDS)->GetStyleTable());
6069
0
}
6070
6071
/************************************************************************/
6072
/*                  GDALDatasetSetStyleTableDirectly()                  */
6073
/************************************************************************/
6074
6075
/**
6076
 \brief Set dataset style table.
6077
6078
 This function operate exactly as GDALDatasetSetStyleTable() except that it
6079
 assumes ownership of the passed table.
6080
6081
 This function is the same as the C++ method
6082
 GDALDataset::SetStyleTableDirectly()
6083
6084
6085
 @param hDS the dataset handle
6086
 @param hStyleTable style table handle to set
6087
6088
*/
6089
6090
void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6091
                                      OGRStyleTableH hStyleTable)
6092
6093
0
{
6094
0
    VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6095
6096
0
    GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6097
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
6098
0
}
6099
6100
/************************************************************************/
6101
/*                      GDALDatasetSetStyleTable()                      */
6102
/************************************************************************/
6103
6104
/**
6105
 \brief Set dataset style table.
6106
6107
 This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6108
 it assumes ownership of the passed table.
6109
6110
 This function is the same as the C++ method GDALDataset::SetStyleTable()
6111
6112
6113
 @param hDS the dataset handle
6114
 @param hStyleTable style table handle to set
6115
6116
*/
6117
6118
void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6119
6120
0
{
6121
0
    VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6122
0
    VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6123
6124
0
    GDALDataset::FromHandle(hDS)->SetStyleTable(
6125
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
6126
0
}
6127
6128
/************************************************************************/
6129
/*                    ValidateLayerCreationOptions()                    */
6130
/************************************************************************/
6131
6132
//! @cond Doxygen_Suppress
6133
int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6134
0
{
6135
0
    const char *pszOptionList =
6136
0
        GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6137
0
    if (pszOptionList == nullptr && poDriver != nullptr)
6138
0
    {
6139
0
        pszOptionList =
6140
0
            poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6141
0
    }
6142
0
    CPLString osDataset;
6143
0
    osDataset.Printf("dataset %s", GetDescription());
6144
0
    return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
6145
0
                               osDataset);
6146
0
}
6147
6148
//! @endcond
6149
6150
/************************************************************************/
6151
/*                              Release()                               */
6152
/************************************************************************/
6153
6154
/**
6155
\brief Drop a reference to this dataset, and if the reference count drops to one
6156
close (destroy) the dataset.
6157
6158
This method is the same as the C function OGRReleaseDataSource().
6159
6160
@deprecated. Use GDALClose() instead
6161
6162
@return OGRERR_NONE on success or an error code.
6163
*/
6164
6165
OGRErr GDALDataset::Release()
6166
6167
0
{
6168
0
    ReleaseRef();
6169
0
    return OGRERR_NONE;
6170
0
}
6171
6172
/************************************************************************/
6173
/*                            GetRefCount()                             */
6174
/************************************************************************/
6175
6176
/**
6177
\brief Fetch reference count.
6178
6179
This method is the same as the C function OGR_DS_GetRefCount().
6180
6181
@return the current reference count for the datasource object itself.
6182
*/
6183
6184
int GDALDataset::GetRefCount() const
6185
0
{
6186
0
    return nRefCount;
6187
0
}
6188
6189
/************************************************************************/
6190
/*                         GetSummaryRefCount()                         */
6191
/************************************************************************/
6192
6193
/**
6194
\brief Fetch reference count of datasource and all owned layers.
6195
6196
This method is the same as the C function  OGR_DS_GetSummaryRefCount().
6197
6198
@deprecated
6199
6200
@return the current summary reference count for the datasource and its layers.
6201
*/
6202
6203
int GDALDataset::GetSummaryRefCount() const
6204
6205
0
{
6206
0
    CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6207
0
    int nSummaryCount = nRefCount;
6208
0
    GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6209
6210
0
    for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6211
0
        nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6212
6213
0
    return nSummaryCount;
6214
0
}
6215
6216
/************************************************************************/
6217
/*                            ICreateLayer()                            */
6218
/************************************************************************/
6219
6220
/**
6221
 \brief This method attempts to create a new layer on the dataset with the
6222
 indicated name, coordinate system, geometry type.
6223
6224
 This method is reserved to implementation by drivers.
6225
6226
 The papszOptions argument can be used to control driver specific creation
6227
 options.  These options are normally documented in the format specific
6228
 documentation.
6229
6230
 @param pszName the name for the new layer.  This should ideally not
6231
 match any existing layer on the datasource.
6232
 @param poGeomFieldDefn the geometry field definition to use for the new layer,
6233
 or NULL if there is no geometry field.
6234
 @param papszOptions a StringList of name=value options.  Options are driver
6235
 specific.
6236
6237
 @return NULL is returned on failure, or a new OGRLayer handle on success.
6238
6239
*/
6240
6241
OGRLayer *
6242
GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6243
                          CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6244
                          CPL_UNUSED CSLConstList papszOptions)
6245
6246
0
{
6247
0
    CPLError(CE_Failure, CPLE_NotSupported,
6248
0
             "CreateLayer() not supported by this dataset.");
6249
6250
0
    return nullptr;
6251
0
}
6252
6253
/************************************************************************/
6254
/*                             CopyLayer()                              */
6255
/************************************************************************/
6256
6257
/**
6258
 \brief Duplicate an existing layer.
6259
6260
 This method creates a new layer, duplicate the field definitions of the
6261
 source layer and then duplicate each features of the source layer.
6262
 The papszOptions argument
6263
 can be used to control driver specific creation options.  These options are
6264
 normally documented in the format specific documentation.
6265
 The source layer may come from another dataset.
6266
6267
 This method is the same as the C function GDALDatasetCopyLayer() and the
6268
 deprecated OGR_DS_CopyLayer().
6269
6270
 @param poSrcLayer source layer.
6271
 @param pszNewName the name of the layer to create.
6272
 @param papszOptions a StringList of name=value options.  Options are driver
6273
                     specific. There is a common option to set output layer
6274
                     spatial reference: DST_SRSWKT. The option should be in
6275
                     WKT format. Starting with GDAL 3.7, the common option
6276
                     COPY_MD can be set to NO to prevent the default copying
6277
                     of the metadata from the source layer to the target layer.
6278
6279
 @return a handle to the layer, or NULL if an error occurs.
6280
*/
6281
6282
OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6283
                                 CSLConstList papszOptions)
6284
6285
0
{
6286
    /* -------------------------------------------------------------------- */
6287
    /*      Create the layer.                                               */
6288
    /* -------------------------------------------------------------------- */
6289
0
    if (!TestCapability(ODsCCreateLayer))
6290
0
    {
6291
0
        CPLError(CE_Failure, CPLE_NotSupported,
6292
0
                 "This datasource does not support creation of layers.");
6293
0
        return nullptr;
6294
0
    }
6295
6296
0
    const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6297
0
    OGRSpatialReference oDstSpaRef(pszSRSWKT);
6298
0
    oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6299
0
    OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6300
0
    OGRLayer *poDstLayer = nullptr;
6301
6302
0
    CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6303
0
    aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6304
0
    aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6305
6306
0
    CPLErrorReset();
6307
0
    const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6308
0
    if (nSrcGeomFieldCount == 1)
6309
0
    {
6310
0
        OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6311
0
        if (pszSRSWKT)
6312
0
            oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6313
0
        poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6314
0
                                  aosCleanedUpOptions.List());
6315
0
    }
6316
0
    else
6317
0
    {
6318
0
        poDstLayer =
6319
0
            ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6320
0
    }
6321
6322
0
    if (poDstLayer == nullptr)
6323
0
        return nullptr;
6324
6325
0
    if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6326
0
    {
6327
0
        CSLConstList papszMD = poSrcLayer->GetMetadata();
6328
0
        if (papszMD)
6329
0
            poDstLayer->SetMetadata(papszMD);
6330
0
    }
6331
6332
    /* -------------------------------------------------------------------- */
6333
    /*      Add fields.  Default to copy all fields, and make sure to       */
6334
    /*      establish a mapping between indices, rather than names, in      */
6335
    /*      case the target datasource has altered it (e.g. Shapefile       */
6336
    /*      limited to 10 char field names).                                */
6337
    /* -------------------------------------------------------------------- */
6338
0
    const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6339
6340
    // Initialize the index-to-index map to -1's.
6341
0
    std::vector<int> anMap(nSrcFieldCount, -1);
6342
6343
    // Caution: At the time of writing, the MapInfo driver
6344
    // returns NULL until a field has been added.
6345
0
    OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6346
0
    int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6347
0
    for (int iField = 0; iField < nSrcFieldCount; ++iField)
6348
0
    {
6349
0
        OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6350
0
        OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6351
6352
        // The field may have been already created at layer creation.
6353
0
        int iDstField = -1;
6354
0
        if (poDstFDefn)
6355
0
            iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6356
0
        if (iDstField >= 0)
6357
0
        {
6358
0
            anMap[iField] = iDstField;
6359
0
        }
6360
0
        else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6361
0
        {
6362
            // Now that we've created a field, GetLayerDefn() won't return NULL.
6363
0
            if (poDstFDefn == nullptr)
6364
0
                poDstFDefn = poDstLayer->GetLayerDefn();
6365
6366
            // Sanity check: if it fails, the driver is buggy.
6367
0
            if (poDstFDefn != nullptr &&
6368
0
                poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6369
0
            {
6370
0
                CPLError(CE_Warning, CPLE_AppDefined,
6371
0
                         "The output driver has claimed to have added the %s "
6372
0
                         "field, but it did not!",
6373
0
                         oFieldDefn.GetNameRef());
6374
0
            }
6375
0
            else
6376
0
            {
6377
0
                anMap[iField] = nDstFieldCount;
6378
0
                ++nDstFieldCount;
6379
0
            }
6380
0
        }
6381
0
    }
6382
6383
    /* -------------------------------------------------------------------- */
6384
0
    std::unique_ptr<OGRCoordinateTransformation> poCT;
6385
0
    const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6386
0
    if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6387
0
        sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6388
0
    {
6389
0
        poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6390
0
        if (nullptr == poCT)
6391
0
        {
6392
0
            CPLError(CE_Failure, CPLE_NotSupported,
6393
0
                     "This input/output spatial reference is not supported.");
6394
0
            return nullptr;
6395
0
        }
6396
0
    }
6397
    /* -------------------------------------------------------------------- */
6398
    /*      Create geometry fields.                                         */
6399
    /* -------------------------------------------------------------------- */
6400
0
    if (nSrcGeomFieldCount > 1 &&
6401
0
        TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6402
0
    {
6403
6404
0
        for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6405
0
        {
6406
0
            if (nullptr == pszSRSWKT)
6407
0
            {
6408
0
                poDstLayer->CreateGeomField(
6409
0
                    poSrcDefn->GetGeomFieldDefn(iField));
6410
0
            }
6411
0
            else
6412
0
            {
6413
0
                OGRGeomFieldDefn *pDstGeomFieldDefn =
6414
0
                    poSrcDefn->GetGeomFieldDefn(iField);
6415
0
                pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6416
0
                poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6417
0
            }
6418
0
        }
6419
0
    }
6420
6421
    /* -------------------------------------------------------------------- */
6422
    /*      Check if the destination layer supports transactions and set a  */
6423
    /*      default number of features in a single transaction.             */
6424
    /* -------------------------------------------------------------------- */
6425
0
    const int nGroupTransactions =
6426
0
        poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6427
6428
    /* -------------------------------------------------------------------- */
6429
    /*      Transfer features.                                              */
6430
    /* -------------------------------------------------------------------- */
6431
0
    poSrcLayer->ResetReading();
6432
6433
0
    if (nGroupTransactions <= 0)
6434
0
    {
6435
0
        while (true)
6436
0
        {
6437
0
            auto poFeature =
6438
0
                std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6439
6440
0
            if (poFeature == nullptr)
6441
0
                break;
6442
6443
0
            CPLErrorReset();
6444
0
            auto poDstFeature =
6445
0
                std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6446
6447
0
            if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6448
0
                OGRERR_NONE)
6449
0
            {
6450
0
                CPLError(CE_Failure, CPLE_AppDefined,
6451
0
                         "Unable to translate feature " CPL_FRMT_GIB
6452
0
                         " from layer %s.",
6453
0
                         poFeature->GetFID(), poSrcDefn->GetName());
6454
0
                return poDstLayer;
6455
0
            }
6456
6457
0
            if (nullptr != poCT)
6458
0
            {
6459
0
                for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6460
0
                {
6461
0
                    OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6462
0
                    if (nullptr == pGeom)
6463
0
                        continue;
6464
6465
0
                    const OGRErr eErr = pGeom->transform(poCT.get());
6466
0
                    if (eErr == OGRERR_NONE)
6467
0
                        continue;
6468
6469
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6470
0
                             "Unable to transform geometry " CPL_FRMT_GIB
6471
0
                             " from layer %s.",
6472
0
                             poFeature->GetFID(), poSrcDefn->GetName());
6473
0
                    return poDstLayer;
6474
0
                }
6475
0
            }
6476
6477
0
            poDstFeature->SetFID(poFeature->GetFID());
6478
6479
0
            CPLErrorReset();
6480
0
            if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6481
0
            {
6482
0
                return poDstLayer;
6483
0
            }
6484
0
        }
6485
0
    }
6486
0
    else
6487
0
    {
6488
0
        std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6489
0
        try
6490
0
        {
6491
0
            apoDstFeatures.resize(nGroupTransactions);
6492
0
        }
6493
0
        catch (const std::exception &e)
6494
0
        {
6495
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6496
0
            return poDstLayer;
6497
0
        }
6498
0
        bool bStopTransfer = false;
6499
0
        while (!bStopTransfer)
6500
0
        {
6501
            /* --------------------------------------------------------------------
6502
             */
6503
            /*      Fill the array with features. */
6504
            /* --------------------------------------------------------------------
6505
             */
6506
            // Number of features in the temporary array.
6507
0
            int nFeatCount = 0;  // Used after for.
6508
0
            for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6509
0
            {
6510
0
                auto poFeature =
6511
0
                    std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6512
6513
0
                if (poFeature == nullptr)
6514
0
                {
6515
0
                    bStopTransfer = true;
6516
0
                    break;
6517
0
                }
6518
6519
0
                CPLErrorReset();
6520
0
                apoDstFeatures[nFeatCount] =
6521
0
                    std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6522
6523
0
                if (apoDstFeatures[nFeatCount]->SetFrom(
6524
0
                        poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6525
0
                {
6526
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6527
0
                             "Unable to translate feature " CPL_FRMT_GIB
6528
0
                             " from layer %s.",
6529
0
                             poFeature->GetFID(), poSrcDefn->GetName());
6530
0
                    bStopTransfer = true;
6531
0
                    poFeature.reset();
6532
0
                    break;
6533
0
                }
6534
6535
0
                if (nullptr != poCT)
6536
0
                {
6537
0
                    for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6538
0
                    {
6539
0
                        OGRGeometry *pGeom =
6540
0
                            apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6541
0
                        if (nullptr == pGeom)
6542
0
                            continue;
6543
6544
0
                        const OGRErr eErr = pGeom->transform(poCT.get());
6545
0
                        if (eErr == OGRERR_NONE)
6546
0
                            continue;
6547
6548
0
                        CPLError(CE_Failure, CPLE_AppDefined,
6549
0
                                 "Unable to transform geometry " CPL_FRMT_GIB
6550
0
                                 " from layer %s.",
6551
0
                                 poFeature->GetFID(), poSrcDefn->GetName());
6552
0
                        bStopTransfer = true;
6553
0
                        poFeature.reset();
6554
0
                        break;
6555
0
                    }
6556
0
                }
6557
6558
0
                if (poFeature)
6559
0
                {
6560
0
                    apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6561
0
                }
6562
0
            }
6563
6564
0
            CPLErrorReset();
6565
0
            bool bStopTransaction = false;
6566
0
            while (!bStopTransaction)
6567
0
            {
6568
0
                bStopTransaction = true;
6569
0
                if (poDstLayer->StartTransaction() != OGRERR_NONE)
6570
0
                    break;
6571
0
                for (int i = 0; i < nFeatCount; ++i)
6572
0
                {
6573
0
                    if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6574
0
                        OGRERR_NONE)
6575
0
                    {
6576
0
                        bStopTransfer = true;
6577
0
                        bStopTransaction = false;
6578
0
                        break;
6579
0
                    }
6580
0
                    apoDstFeatures[i].reset();
6581
0
                }
6582
0
                if (bStopTransaction)
6583
0
                {
6584
0
                    if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6585
0
                        break;
6586
0
                }
6587
0
                else
6588
0
                {
6589
0
                    poDstLayer->RollbackTransaction();
6590
0
                }
6591
0
            }
6592
0
        }
6593
0
    }
6594
6595
0
    return poDstLayer;
6596
0
}
6597
6598
/************************************************************************/
6599
/*                            DeleteLayer()                             */
6600
/************************************************************************/
6601
6602
/**
6603
 \fn GDALDataset::DeleteLayer(int)
6604
 \brief Delete the indicated layer from the datasource.
6605
6606
 If this method is supported
6607
 the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6608
6609
 This method is the same as the C function GDALDatasetDeleteLayer() and the
6610
 deprecated OGR_DS_DeleteLayer().
6611
6612
 @param iLayer the index of the layer to delete.
6613
6614
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6615
 layers is not supported for this datasource.
6616
6617
*/
6618
6619
OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6620
6621
0
{
6622
0
    CPLError(CE_Failure, CPLE_NotSupported,
6623
0
             "DeleteLayer() not supported by this dataset.");
6624
6625
0
    return OGRERR_UNSUPPORTED_OPERATION;
6626
0
}
6627
6628
/************************************************************************/
6629
/*                           GetLayerByName()                           */
6630
/************************************************************************/
6631
6632
/**
6633
 \brief Fetch a layer by name.
6634
6635
 The returned layer remains owned by the
6636
 GDALDataset and should not be deleted by the application.
6637
6638
 This method is the same as the C function GDALDatasetGetLayerByName() and the
6639
 deprecated OGR_DS_GetLayerByName().
6640
6641
 @param pszName the layer name of the layer to fetch.
6642
6643
 @return the layer, or NULL if Layer is not found or an error occurs.
6644
*/
6645
6646
OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6647
6648
0
{
6649
0
    CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6650
6651
0
    if (!pszName)
6652
0
        return nullptr;
6653
6654
    // First a case sensitive check.
6655
0
    for (auto *poLayer : GetLayers())
6656
0
    {
6657
0
        if (strcmp(pszName, poLayer->GetName()) == 0)
6658
0
            return poLayer;
6659
0
    }
6660
6661
    // Then case insensitive.
6662
0
    for (auto *poLayer : GetLayers())
6663
0
    {
6664
0
        if (EQUAL(pszName, poLayer->GetName()))
6665
0
            return poLayer;
6666
0
    }
6667
6668
0
    return nullptr;
6669
0
}
6670
6671
//! @cond Doxygen_Suppress
6672
/************************************************************************/
6673
/*                       ProcessSQLCreateIndex()                        */
6674
/*                                                                      */
6675
/*      The correct syntax for creating an index in our dialect of      */
6676
/*      SQL is:                                                         */
6677
/*                                                                      */
6678
/*        CREATE INDEX ON <layername> USING <columnname>                */
6679
/************************************************************************/
6680
6681
OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6682
6683
0
{
6684
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6685
6686
    /* -------------------------------------------------------------------- */
6687
    /*      Do some general syntax checking.                                */
6688
    /* -------------------------------------------------------------------- */
6689
0
    if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6690
0
        !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6691
0
        !EQUAL(papszTokens[4], "USING"))
6692
0
    {
6693
0
        CSLDestroy(papszTokens);
6694
0
        CPLError(CE_Failure, CPLE_AppDefined,
6695
0
                 "Syntax error in CREATE INDEX command.\n"
6696
0
                 "Was '%s'\n"
6697
0
                 "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6698
0
                 pszSQLCommand);
6699
0
        return OGRERR_FAILURE;
6700
0
    }
6701
6702
    /* -------------------------------------------------------------------- */
6703
    /*      Find the named layer.                                           */
6704
    /* -------------------------------------------------------------------- */
6705
0
    OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6706
0
    if (poLayer == nullptr)
6707
0
    {
6708
0
        CPLError(CE_Failure, CPLE_AppDefined,
6709
0
                 "CREATE INDEX ON failed, no such layer as `%s'.",
6710
0
                 papszTokens[3]);
6711
0
        CSLDestroy(papszTokens);
6712
0
        return OGRERR_FAILURE;
6713
0
    }
6714
6715
    /* -------------------------------------------------------------------- */
6716
    /*      Does this layer even support attribute indexes?                 */
6717
    /* -------------------------------------------------------------------- */
6718
0
    if (poLayer->GetIndex() == nullptr)
6719
0
    {
6720
0
        CPLError(CE_Failure, CPLE_AppDefined,
6721
0
                 "CREATE INDEX ON not supported by this driver.");
6722
0
        CSLDestroy(papszTokens);
6723
0
        return OGRERR_FAILURE;
6724
0
    }
6725
6726
    /* -------------------------------------------------------------------- */
6727
    /*      Find the named field.                                           */
6728
    /* -------------------------------------------------------------------- */
6729
0
    int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6730
6731
0
    CSLDestroy(papszTokens);
6732
6733
0
    if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6734
0
    {
6735
0
        CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6736
0
                 pszSQLCommand);
6737
0
        return OGRERR_FAILURE;
6738
0
    }
6739
6740
    /* -------------------------------------------------------------------- */
6741
    /*      Attempt to create the index.                                    */
6742
    /* -------------------------------------------------------------------- */
6743
0
    OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6744
0
    if (eErr == OGRERR_NONE)
6745
0
    {
6746
0
        eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6747
0
    }
6748
0
    else
6749
0
    {
6750
0
        if (strlen(CPLGetLastErrorMsg()) == 0)
6751
0
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6752
0
    }
6753
6754
0
    return eErr;
6755
0
}
6756
6757
/************************************************************************/
6758
/*                        ProcessSQLDropIndex()                         */
6759
/*                                                                      */
6760
/*      The correct syntax for dropping one or more indexes in          */
6761
/*      the OGR SQL dialect is:                                         */
6762
/*                                                                      */
6763
/*          DROP INDEX ON <layername> [USING <columnname>]              */
6764
/************************************************************************/
6765
6766
OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6767
6768
0
{
6769
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6770
6771
    /* -------------------------------------------------------------------- */
6772
    /*      Do some general syntax checking.                                */
6773
    /* -------------------------------------------------------------------- */
6774
0
    if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6775
0
        !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6776
0
        !EQUAL(papszTokens[2], "ON") ||
6777
0
        (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6778
0
    {
6779
0
        CSLDestroy(papszTokens);
6780
0
        CPLError(CE_Failure, CPLE_AppDefined,
6781
0
                 "Syntax error in DROP INDEX command.\n"
6782
0
                 "Was '%s'\n"
6783
0
                 "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6784
0
                 pszSQLCommand);
6785
0
        return OGRERR_FAILURE;
6786
0
    }
6787
6788
    /* -------------------------------------------------------------------- */
6789
    /*      Find the named layer.                                           */
6790
    /* -------------------------------------------------------------------- */
6791
0
    OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6792
0
    if (poLayer == nullptr)
6793
0
    {
6794
0
        CPLError(CE_Failure, CPLE_AppDefined,
6795
0
                 "DROP INDEX ON failed, no such layer as `%s'.",
6796
0
                 papszTokens[3]);
6797
0
        CSLDestroy(papszTokens);
6798
0
        return OGRERR_FAILURE;
6799
0
    }
6800
6801
    /* -------------------------------------------------------------------- */
6802
    /*      Does this layer even support attribute indexes?                 */
6803
    /* -------------------------------------------------------------------- */
6804
0
    if (poLayer->GetIndex() == nullptr)
6805
0
    {
6806
0
        CPLError(CE_Failure, CPLE_AppDefined,
6807
0
                 "Indexes not supported by this driver.");
6808
0
        CSLDestroy(papszTokens);
6809
0
        return OGRERR_FAILURE;
6810
0
    }
6811
6812
    /* -------------------------------------------------------------------- */
6813
    /*      If we were not given a field name, drop all indexes.            */
6814
    /* -------------------------------------------------------------------- */
6815
0
    if (CSLCount(papszTokens) == 4)
6816
0
    {
6817
0
        for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6818
0
        {
6819
0
            OGRAttrIndex *poAttrIndex;
6820
6821
0
            poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6822
0
            if (poAttrIndex != nullptr)
6823
0
            {
6824
0
                const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6825
0
                if (eErr != OGRERR_NONE)
6826
0
                {
6827
0
                    CSLDestroy(papszTokens);
6828
0
                    return eErr;
6829
0
                }
6830
0
            }
6831
0
        }
6832
6833
0
        CSLDestroy(papszTokens);
6834
0
        return OGRERR_NONE;
6835
0
    }
6836
6837
    /* -------------------------------------------------------------------- */
6838
    /*      Find the named field.                                           */
6839
    /* -------------------------------------------------------------------- */
6840
0
    int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6841
0
    CSLDestroy(papszTokens);
6842
6843
0
    if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6844
0
    {
6845
0
        CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6846
0
                 pszSQLCommand);
6847
0
        return OGRERR_FAILURE;
6848
0
    }
6849
6850
    /* -------------------------------------------------------------------- */
6851
    /*      Attempt to drop the index.                                      */
6852
    /* -------------------------------------------------------------------- */
6853
0
    const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6854
6855
0
    return eErr;
6856
0
}
6857
6858
/************************************************************************/
6859
/*                        ProcessSQLDropTable()                         */
6860
/*                                                                      */
6861
/*      The correct syntax for dropping a table (layer) in the OGR SQL  */
6862
/*      dialect is:                                                     */
6863
/*                                                                      */
6864
/*          DROP TABLE <layername>                                      */
6865
/************************************************************************/
6866
6867
OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6868
6869
0
{
6870
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6871
6872
    /* -------------------------------------------------------------------- */
6873
    /*      Do some general syntax checking.                                */
6874
    /* -------------------------------------------------------------------- */
6875
0
    if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6876
0
        !EQUAL(papszTokens[1], "TABLE"))
6877
0
    {
6878
0
        CSLDestroy(papszTokens);
6879
0
        CPLError(CE_Failure, CPLE_AppDefined,
6880
0
                 "Syntax error in DROP TABLE command.\n"
6881
0
                 "Was '%s'\n"
6882
0
                 "Should be of form 'DROP TABLE <table>'",
6883
0
                 pszSQLCommand);
6884
0
        return OGRERR_FAILURE;
6885
0
    }
6886
6887
    /* -------------------------------------------------------------------- */
6888
    /*      Find the named layer.                                           */
6889
    /* -------------------------------------------------------------------- */
6890
0
    OGRLayer *poLayer = nullptr;
6891
6892
0
    int i = 0;  // Used after for.
6893
0
    for (; i < GetLayerCount(); ++i)
6894
0
    {
6895
0
        poLayer = GetLayer(i);
6896
6897
0
        if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6898
0
            break;
6899
0
        poLayer = nullptr;
6900
0
    }
6901
6902
0
    if (poLayer == nullptr)
6903
0
    {
6904
0
        CPLError(CE_Failure, CPLE_AppDefined,
6905
0
                 "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6906
0
        CSLDestroy(papszTokens);
6907
0
        return OGRERR_FAILURE;
6908
0
    }
6909
6910
0
    CSLDestroy(papszTokens);
6911
6912
    /* -------------------------------------------------------------------- */
6913
    /*      Delete it.                                                      */
6914
    /* -------------------------------------------------------------------- */
6915
6916
0
    return DeleteLayer(i);
6917
0
}
6918
6919
//! @endcond
6920
6921
/************************************************************************/
6922
/*                      GDALDatasetParseSQLType()                       */
6923
/************************************************************************/
6924
6925
/* All arguments will be altered */
6926
static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6927
                                            int &nPrecision)
6928
0
{
6929
0
    char *pszParenthesis = strchr(pszType, '(');
6930
0
    if (pszParenthesis)
6931
0
    {
6932
0
        nWidth = atoi(pszParenthesis + 1);
6933
0
        *pszParenthesis = '\0';
6934
0
        char *pszComma = strchr(pszParenthesis + 1, ',');
6935
0
        if (pszComma)
6936
0
            nPrecision = atoi(pszComma + 1);
6937
0
    }
6938
6939
0
    OGRFieldType eType = OFTString;
6940
0
    if (EQUAL(pszType, "INTEGER"))
6941
0
        eType = OFTInteger;
6942
0
    else if (EQUAL(pszType, "INTEGER[]"))
6943
0
        eType = OFTIntegerList;
6944
0
    else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6945
0
             EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6946
0
             EQUAL(pszType, "REAL") /* unofficial alias */)
6947
0
        eType = OFTReal;
6948
0
    else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6949
0
             EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6950
0
             EQUAL(pszType, "REAL[]") /* unofficial alias */)
6951
0
        eType = OFTRealList;
6952
0
    else if (EQUAL(pszType, "CHARACTER") ||
6953
0
             EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6954
0
             EQUAL(pszType, "STRING") /* unofficial alias */ ||
6955
0
             EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6956
0
        eType = OFTString;
6957
0
    else if (EQUAL(pszType, "TEXT[]") ||
6958
0
             EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6959
0
             EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6960
0
        eType = OFTStringList;
6961
0
    else if (EQUAL(pszType, "DATE"))
6962
0
        eType = OFTDate;
6963
0
    else if (EQUAL(pszType, "TIME"))
6964
0
        eType = OFTTime;
6965
0
    else if (EQUAL(pszType, "TIMESTAMP") ||
6966
0
             EQUAL(pszType, "DATETIME") /* unofficial alias */)
6967
0
        eType = OFTDateTime;
6968
0
    else
6969
0
        CPLError(CE_Warning, CPLE_NotSupported,
6970
0
                 "Unsupported column type '%s'. Defaulting to VARCHAR",
6971
0
                 pszType);
6972
6973
0
    return eType;
6974
0
}
6975
6976
/************************************************************************/
6977
/*                    ProcessSQLAlterTableAddColumn()                   */
6978
/*                                                                      */
6979
/*      The correct syntax for adding a column in the OGR SQL           */
6980
/*      dialect is:                                                     */
6981
/*                                                                      */
6982
/*       ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6983
/************************************************************************/
6984
6985
//! @cond Doxygen_Suppress
6986
OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6987
6988
0
{
6989
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6990
6991
    /* -------------------------------------------------------------------- */
6992
    /*      Do some general syntax checking.                                */
6993
    /* -------------------------------------------------------------------- */
6994
0
    const char *pszLayerName = nullptr;
6995
0
    const char *pszColumnName = nullptr;
6996
0
    int iTypeIndex = 0;
6997
0
    const int nTokens = CSLCount(papszTokens);
6998
6999
0
    if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7000
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
7001
0
        EQUAL(papszTokens[4], "COLUMN"))
7002
0
    {
7003
0
        pszLayerName = papszTokens[2];
7004
0
        pszColumnName = papszTokens[5];
7005
0
        iTypeIndex = 6;
7006
0
    }
7007
0
    else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
7008
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
7009
0
    {
7010
0
        pszLayerName = papszTokens[2];
7011
0
        pszColumnName = papszTokens[4];
7012
0
        iTypeIndex = 5;
7013
0
    }
7014
0
    else
7015
0
    {
7016
0
        CSLDestroy(papszTokens);
7017
0
        CPLError(CE_Failure, CPLE_AppDefined,
7018
0
                 "Syntax error in ALTER TABLE ADD COLUMN command.\n"
7019
0
                 "Was '%s'\n"
7020
0
                 "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
7021
0
                 "<columnname> <columntype>'",
7022
0
                 pszSQLCommand);
7023
0
        return OGRERR_FAILURE;
7024
0
    }
7025
7026
    /* -------------------------------------------------------------------- */
7027
    /*      Merge type components into a single string if there were split  */
7028
    /*      with spaces                                                     */
7029
    /* -------------------------------------------------------------------- */
7030
0
    CPLString osType;
7031
0
    for (int i = iTypeIndex; i < nTokens; ++i)
7032
0
    {
7033
0
        osType += papszTokens[i];
7034
0
        CPLFree(papszTokens[i]);
7035
0
    }
7036
0
    char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7037
0
    papszTokens[iTypeIndex + 1] = nullptr;
7038
7039
    /* -------------------------------------------------------------------- */
7040
    /*      Find the named layer.                                           */
7041
    /* -------------------------------------------------------------------- */
7042
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7043
0
    if (poLayer == nullptr)
7044
0
    {
7045
0
        CPLError(CE_Failure, CPLE_AppDefined,
7046
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7047
0
                 pszLayerName);
7048
0
        CSLDestroy(papszTokens);
7049
0
        return OGRERR_FAILURE;
7050
0
    }
7051
7052
    /* -------------------------------------------------------------------- */
7053
    /*      Add column.                                                     */
7054
    /* -------------------------------------------------------------------- */
7055
7056
0
    int nWidth = 0;
7057
0
    int nPrecision = 0;
7058
0
    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7059
0
    OGRFieldDefn oFieldDefn(pszColumnName, eType);
7060
0
    oFieldDefn.SetWidth(nWidth);
7061
0
    oFieldDefn.SetPrecision(nPrecision);
7062
7063
0
    CSLDestroy(papszTokens);
7064
7065
0
    return poLayer->CreateField(&oFieldDefn);
7066
0
}
7067
7068
/************************************************************************/
7069
/*                    ProcessSQLAlterTableDropColumn()                  */
7070
/*                                                                      */
7071
/*      The correct syntax for dropping a column in the OGR SQL         */
7072
/*      dialect is:                                                     */
7073
/*                                                                      */
7074
/*          ALTER TABLE <layername> DROP [COLUMN] <columnname>          */
7075
/************************************************************************/
7076
7077
OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7078
7079
0
{
7080
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7081
7082
    /* -------------------------------------------------------------------- */
7083
    /*      Do some general syntax checking.                                */
7084
    /* -------------------------------------------------------------------- */
7085
0
    const char *pszLayerName = nullptr;
7086
0
    const char *pszColumnName = nullptr;
7087
0
    if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7088
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7089
0
        EQUAL(papszTokens[4], "COLUMN"))
7090
0
    {
7091
0
        pszLayerName = papszTokens[2];
7092
0
        pszColumnName = papszTokens[5];
7093
0
    }
7094
0
    else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7095
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7096
0
    {
7097
0
        pszLayerName = papszTokens[2];
7098
0
        pszColumnName = papszTokens[4];
7099
0
    }
7100
0
    else
7101
0
    {
7102
0
        CSLDestroy(papszTokens);
7103
0
        CPLError(CE_Failure, CPLE_AppDefined,
7104
0
                 "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7105
0
                 "Was '%s'\n"
7106
0
                 "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7107
0
                 "<columnname>'",
7108
0
                 pszSQLCommand);
7109
0
        return OGRERR_FAILURE;
7110
0
    }
7111
7112
    /* -------------------------------------------------------------------- */
7113
    /*      Find the named layer.                                           */
7114
    /* -------------------------------------------------------------------- */
7115
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7116
0
    if (poLayer == nullptr)
7117
0
    {
7118
0
        CPLError(CE_Failure, CPLE_AppDefined,
7119
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7120
0
                 pszLayerName);
7121
0
        CSLDestroy(papszTokens);
7122
0
        return OGRERR_FAILURE;
7123
0
    }
7124
7125
    /* -------------------------------------------------------------------- */
7126
    /*      Find the field.                                                 */
7127
    /* -------------------------------------------------------------------- */
7128
7129
0
    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7130
0
    if (nFieldIndex < 0)
7131
0
    {
7132
0
        CPLError(CE_Failure, CPLE_AppDefined,
7133
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7134
0
                 pszColumnName);
7135
0
        CSLDestroy(papszTokens);
7136
0
        return OGRERR_FAILURE;
7137
0
    }
7138
7139
    /* -------------------------------------------------------------------- */
7140
    /*      Remove it.                                                      */
7141
    /* -------------------------------------------------------------------- */
7142
7143
0
    CSLDestroy(papszTokens);
7144
7145
0
    return poLayer->DeleteField(nFieldIndex);
7146
0
}
7147
7148
/************************************************************************/
7149
/*                 ProcessSQLAlterTableRenameColumn()                   */
7150
/*                                                                      */
7151
/*      The correct syntax for renaming a column in the OGR SQL         */
7152
/*      dialect is:                                                     */
7153
/*                                                                      */
7154
/*       ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7155
/************************************************************************/
7156
7157
OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7158
7159
0
{
7160
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7161
7162
    /* -------------------------------------------------------------------- */
7163
    /*      Do some general syntax checking.                                */
7164
    /* -------------------------------------------------------------------- */
7165
0
    const char *pszLayerName = nullptr;
7166
0
    const char *pszOldColName = nullptr;
7167
0
    const char *pszNewColName = nullptr;
7168
0
    if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7169
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7170
0
        EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7171
0
    {
7172
0
        pszLayerName = papszTokens[2];
7173
0
        pszOldColName = papszTokens[5];
7174
0
        pszNewColName = papszTokens[7];
7175
0
    }
7176
0
    else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7177
0
             EQUAL(papszTokens[1], "TABLE") &&
7178
0
             EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7179
0
    {
7180
0
        pszLayerName = papszTokens[2];
7181
0
        pszOldColName = papszTokens[4];
7182
0
        pszNewColName = papszTokens[6];
7183
0
    }
7184
0
    else
7185
0
    {
7186
0
        CSLDestroy(papszTokens);
7187
0
        CPLError(CE_Failure, CPLE_AppDefined,
7188
0
                 "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7189
0
                 "Was '%s'\n"
7190
0
                 "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7191
0
                 "<columnname> TO <newname>'",
7192
0
                 pszSQLCommand);
7193
0
        return OGRERR_FAILURE;
7194
0
    }
7195
7196
    /* -------------------------------------------------------------------- */
7197
    /*      Find the named layer.                                           */
7198
    /* -------------------------------------------------------------------- */
7199
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7200
0
    if (poLayer == nullptr)
7201
0
    {
7202
0
        CPLError(CE_Failure, CPLE_AppDefined,
7203
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7204
0
                 pszLayerName);
7205
0
        CSLDestroy(papszTokens);
7206
0
        return OGRERR_FAILURE;
7207
0
    }
7208
7209
    /* -------------------------------------------------------------------- */
7210
    /*      Find the field.                                                 */
7211
    /* -------------------------------------------------------------------- */
7212
7213
0
    const int nFieldIndex =
7214
0
        poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7215
0
    if (nFieldIndex < 0)
7216
0
    {
7217
0
        CPLError(CE_Failure, CPLE_AppDefined,
7218
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7219
0
                 pszOldColName);
7220
0
        CSLDestroy(papszTokens);
7221
0
        return OGRERR_FAILURE;
7222
0
    }
7223
7224
    /* -------------------------------------------------------------------- */
7225
    /*      Rename column.                                                  */
7226
    /* -------------------------------------------------------------------- */
7227
0
    OGRFieldDefn *poOldFieldDefn =
7228
0
        poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7229
0
    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7230
0
    oNewFieldDefn.SetName(pszNewColName);
7231
7232
0
    CSLDestroy(papszTokens);
7233
7234
0
    return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7235
0
                                   ALTER_NAME_FLAG);
7236
0
}
7237
7238
/************************************************************************/
7239
/*                 ProcessSQLAlterTableAlterColumn()                    */
7240
/*                                                                      */
7241
/*      The correct syntax for altering the type of a column in the     */
7242
/*      OGR SQL dialect is:                                             */
7243
/*                                                                      */
7244
/*   ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7245
/************************************************************************/
7246
7247
OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7248
7249
0
{
7250
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7251
7252
    /* -------------------------------------------------------------------- */
7253
    /*      Do some general syntax checking.                                */
7254
    /* -------------------------------------------------------------------- */
7255
0
    const char *pszLayerName = nullptr;
7256
0
    const char *pszColumnName = nullptr;
7257
0
    int iTypeIndex = 0;
7258
0
    const int nTokens = CSLCount(papszTokens);
7259
7260
0
    if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7261
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7262
0
        EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7263
0
    {
7264
0
        pszLayerName = papszTokens[2];
7265
0
        pszColumnName = papszTokens[5];
7266
0
        iTypeIndex = 7;
7267
0
    }
7268
0
    else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7269
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7270
0
             EQUAL(papszTokens[5], "TYPE"))
7271
0
    {
7272
0
        pszLayerName = papszTokens[2];
7273
0
        pszColumnName = papszTokens[4];
7274
0
        iTypeIndex = 6;
7275
0
    }
7276
0
    else
7277
0
    {
7278
0
        CSLDestroy(papszTokens);
7279
0
        CPLError(CE_Failure, CPLE_AppDefined,
7280
0
                 "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7281
0
                 "Was '%s'\n"
7282
0
                 "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7283
0
                 "<columnname> TYPE <columntype>'",
7284
0
                 pszSQLCommand);
7285
0
        return OGRERR_FAILURE;
7286
0
    }
7287
7288
    /* -------------------------------------------------------------------- */
7289
    /*      Merge type components into a single string if there were split  */
7290
    /*      with spaces                                                     */
7291
    /* -------------------------------------------------------------------- */
7292
0
    CPLString osType;
7293
0
    for (int i = iTypeIndex; i < nTokens; ++i)
7294
0
    {
7295
0
        osType += papszTokens[i];
7296
0
        CPLFree(papszTokens[i]);
7297
0
    }
7298
0
    char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7299
0
    papszTokens[iTypeIndex + 1] = nullptr;
7300
7301
    /* -------------------------------------------------------------------- */
7302
    /*      Find the named layer.                                           */
7303
    /* -------------------------------------------------------------------- */
7304
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7305
0
    if (poLayer == nullptr)
7306
0
    {
7307
0
        CPLError(CE_Failure, CPLE_AppDefined,
7308
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7309
0
                 pszLayerName);
7310
0
        CSLDestroy(papszTokens);
7311
0
        return OGRERR_FAILURE;
7312
0
    }
7313
7314
    /* -------------------------------------------------------------------- */
7315
    /*      Find the field.                                                 */
7316
    /* -------------------------------------------------------------------- */
7317
7318
0
    const int nFieldIndex =
7319
0
        poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7320
0
    if (nFieldIndex < 0)
7321
0
    {
7322
0
        CPLError(CE_Failure, CPLE_AppDefined,
7323
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7324
0
                 pszColumnName);
7325
0
        CSLDestroy(papszTokens);
7326
0
        return OGRERR_FAILURE;
7327
0
    }
7328
7329
    /* -------------------------------------------------------------------- */
7330
    /*      Alter column.                                                   */
7331
    /* -------------------------------------------------------------------- */
7332
7333
0
    OGRFieldDefn *poOldFieldDefn =
7334
0
        poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7335
0
    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7336
7337
0
    int nWidth = 0;
7338
0
    int nPrecision = 0;
7339
0
    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7340
0
    oNewFieldDefn.SetType(eType);
7341
0
    oNewFieldDefn.SetWidth(nWidth);
7342
0
    oNewFieldDefn.SetPrecision(nPrecision);
7343
7344
0
    int l_nFlags = 0;
7345
0
    if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7346
0
        l_nFlags |= ALTER_TYPE_FLAG;
7347
0
    if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7348
0
        poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7349
0
        l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7350
7351
0
    CSLDestroy(papszTokens);
7352
7353
0
    if (l_nFlags == 0)
7354
0
        return OGRERR_NONE;
7355
7356
0
    return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7357
0
}
7358
7359
//! @endcond
7360
7361
/************************************************************************/
7362
/*                             ExecuteSQL()                             */
7363
/************************************************************************/
7364
7365
/**
7366
 \brief Execute an SQL statement against the data store.
7367
7368
 The result of an SQL query is either NULL for statements that are in error,
7369
 or that have no results set, or an OGRLayer pointer representing a results
7370
 set from the query.  Note that this OGRLayer is in addition to the layers
7371
 in the data store and must be destroyed with
7372
 ReleaseResultSet() before the dataset is closed
7373
 (destroyed).
7374
7375
 This method is the same as the C function GDALDatasetExecuteSQL() and the
7376
 deprecated OGR_DS_ExecuteSQL().
7377
7378
 For more information on the SQL dialect supported internally by OGR
7379
 review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7380
 document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7381
 to the underlying RDBMS.
7382
7383
 Starting with OGR 1.10, the <a
7384
 href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7385
 also be used.
7386
7387
 @param pszStatement the SQL statement to execute.
7388
 @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7389
 @param pszDialect allows control of the statement dialect. If set to NULL, the
7390
 OGR SQL engine will be used, except for RDBMS drivers that will use their
7391
 dedicated SQL engine, unless OGRSQL is explicitly passed as the
7392
 dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7393
7394
 @return an OGRLayer containing the results of the query.  Deallocate with
7395
 ReleaseResultSet().
7396
7397
*/
7398
7399
OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7400
                                  OGRGeometry *poSpatialFilter,
7401
                                  const char *pszDialect)
7402
7403
0
{
7404
0
    return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7405
0
}
7406
7407
//! @cond Doxygen_Suppress
7408
OGRLayer *
7409
GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7410
                        const char *pszDialect,
7411
                        swq_select_parse_options *poSelectParseOptions)
7412
7413
0
{
7414
0
    if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7415
0
    {
7416
#ifdef SQLITE_ENABLED
7417
        return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7418
                                   pszDialect);
7419
#else
7420
0
        CPLError(CE_Failure, CPLE_NotSupported,
7421
0
                 "The SQLite driver needs to be compiled to support the "
7422
0
                 "SQLite SQL dialect");
7423
0
        return nullptr;
7424
0
#endif
7425
0
    }
7426
7427
0
    if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7428
0
        !EQUAL(pszDialect, "OGRSQL"))
7429
0
    {
7430
0
        std::string osDialectList = "'OGRSQL'";
7431
#ifdef SQLITE_ENABLED
7432
        osDialectList += ", 'SQLITE'";
7433
#endif
7434
0
        const char *pszDialects =
7435
0
            GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7436
0
        if (pszDialects)
7437
0
        {
7438
0
            const CPLStringList aosTokens(
7439
0
                CSLTokenizeString2(pszDialects, " ", 0));
7440
0
            for (int i = 0; i < aosTokens.size(); ++i)
7441
0
            {
7442
0
                if (!EQUAL(aosTokens[i], "OGRSQL") &&
7443
0
                    !EQUAL(aosTokens[i], "SQLITE"))
7444
0
                {
7445
0
                    osDialectList += ", '";
7446
0
                    osDialectList += aosTokens[i];
7447
0
                    osDialectList += "'";
7448
0
                }
7449
0
            }
7450
0
        }
7451
0
        CPLError(CE_Warning, CPLE_NotSupported,
7452
0
                 "Dialect '%s' is unsupported. Only supported dialects are %s. "
7453
0
                 "Defaulting to OGRSQL",
7454
0
                 pszDialect, osDialectList.c_str());
7455
0
    }
7456
7457
    /* -------------------------------------------------------------------- */
7458
    /*      Handle CREATE INDEX statements specially.                       */
7459
    /* -------------------------------------------------------------------- */
7460
0
    if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7461
0
    {
7462
0
        ProcessSQLCreateIndex(pszStatement);
7463
0
        return nullptr;
7464
0
    }
7465
7466
    /* -------------------------------------------------------------------- */
7467
    /*      Handle DROP INDEX statements specially.                         */
7468
    /* -------------------------------------------------------------------- */
7469
0
    if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7470
0
    {
7471
0
        ProcessSQLDropIndex(pszStatement);
7472
0
        return nullptr;
7473
0
    }
7474
7475
    /* -------------------------------------------------------------------- */
7476
    /*      Handle DROP TABLE statements specially.                         */
7477
    /* -------------------------------------------------------------------- */
7478
0
    if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7479
0
    {
7480
0
        ProcessSQLDropTable(pszStatement);
7481
0
        return nullptr;
7482
0
    }
7483
7484
    /* -------------------------------------------------------------------- */
7485
    /*      Handle ALTER TABLE statements specially.                        */
7486
    /* -------------------------------------------------------------------- */
7487
0
    if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7488
0
    {
7489
0
        char **papszTokens = CSLTokenizeString(pszStatement);
7490
0
        const int nTokens = CSLCount(papszTokens);
7491
0
        if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7492
0
        {
7493
0
            ProcessSQLAlterTableAddColumn(pszStatement);
7494
0
            CSLDestroy(papszTokens);
7495
0
            return nullptr;
7496
0
        }
7497
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7498
0
        {
7499
0
            ProcessSQLAlterTableDropColumn(pszStatement);
7500
0
            CSLDestroy(papszTokens);
7501
0
            return nullptr;
7502
0
        }
7503
0
        else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7504
0
                 EQUAL(papszTokens[4], "TO"))
7505
0
        {
7506
0
            const char *pszSrcTableName = papszTokens[2];
7507
0
            const char *pszDstTableName = papszTokens[5];
7508
0
            auto poSrcLayer = GetLayerByName(pszSrcTableName);
7509
0
            if (poSrcLayer)
7510
0
            {
7511
0
                CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7512
0
            }
7513
0
            else
7514
0
            {
7515
0
                CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7516
0
            }
7517
0
            CSLDestroy(papszTokens);
7518
0
            return nullptr;
7519
0
        }
7520
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7521
0
        {
7522
0
            ProcessSQLAlterTableRenameColumn(pszStatement);
7523
0
            CSLDestroy(papszTokens);
7524
0
            return nullptr;
7525
0
        }
7526
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7527
0
        {
7528
0
            ProcessSQLAlterTableAlterColumn(pszStatement);
7529
0
            CSLDestroy(papszTokens);
7530
0
            return nullptr;
7531
0
        }
7532
0
        else
7533
0
        {
7534
0
            CPLError(CE_Failure, CPLE_AppDefined,
7535
0
                     "Unsupported ALTER TABLE command : %s", pszStatement);
7536
0
            CSLDestroy(papszTokens);
7537
0
            return nullptr;
7538
0
        }
7539
0
    }
7540
7541
    /* -------------------------------------------------------------------- */
7542
    /*      Preparse the SQL statement.                                     */
7543
    /* -------------------------------------------------------------------- */
7544
0
    swq_select *psSelectInfo = new swq_select();
7545
0
    swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7546
0
    if (poSelectParseOptions != nullptr)
7547
0
        poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7548
0
    if (psSelectInfo->preparse(pszStatement,
7549
0
                               poCustomFuncRegistrar != nullptr) != CE_None)
7550
0
    {
7551
0
        delete psSelectInfo;
7552
0
        return nullptr;
7553
0
    }
7554
7555
    /* -------------------------------------------------------------------- */
7556
    /*      If there is no UNION ALL, build result layer.                   */
7557
    /* -------------------------------------------------------------------- */
7558
0
    if (psSelectInfo->poOtherSelect == nullptr)
7559
0
    {
7560
0
        return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7561
0
                                        pszDialect, poSelectParseOptions);
7562
0
    }
7563
7564
    /* -------------------------------------------------------------------- */
7565
    /*      Build result union layer.                                       */
7566
    /* -------------------------------------------------------------------- */
7567
0
    int nSrcLayers = 0;
7568
0
    OGRLayer **papoSrcLayers = nullptr;
7569
7570
0
    do
7571
0
    {
7572
0
        swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7573
0
        psSelectInfo->poOtherSelect = nullptr;
7574
7575
0
        OGRLayer *poLayer = BuildLayerFromSelectInfo(
7576
0
            psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7577
0
        if (poLayer == nullptr)
7578
0
        {
7579
            // Each source layer owns an independent select info.
7580
0
            for (int i = 0; i < nSrcLayers; ++i)
7581
0
                delete papoSrcLayers[i];
7582
0
            CPLFree(papoSrcLayers);
7583
7584
            // So we just have to destroy the remaining select info.
7585
0
            delete psNextSelectInfo;
7586
7587
0
            return nullptr;
7588
0
        }
7589
0
        else
7590
0
        {
7591
0
            papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7592
0
                papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7593
0
            papoSrcLayers[nSrcLayers] = poLayer;
7594
0
            ++nSrcLayers;
7595
7596
0
            psSelectInfo = psNextSelectInfo;
7597
0
        }
7598
0
    } while (psSelectInfo != nullptr);
7599
7600
0
    return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7601
0
}
7602
7603
//! @endcond
7604
7605
/************************************************************************/
7606
/*                              AbortSQL()                              */
7607
/************************************************************************/
7608
7609
/**
7610
 \brief Abort any SQL statement running in the data store.
7611
7612
 This function can be safely called from any thread (pending that the dataset
7613
 object is still alive). Driver implementations will make sure that it can be
7614
 called in a thread-safe way.
7615
7616
 This might not be implemented by all drivers. At time of writing, only SQLite,
7617
 GPKG and PG drivers implement it
7618
7619
 This method is the same as the C method GDALDatasetAbortSQL()
7620
7621
 @since GDAL 3.2.0
7622
7623
7624
*/
7625
7626
OGRErr GDALDataset::AbortSQL()
7627
0
{
7628
0
    CPLError(CE_Failure, CPLE_NotSupported,
7629
0
             "AbortSQL is not supported for this driver.");
7630
0
    return OGRERR_UNSUPPORTED_OPERATION;
7631
0
}
7632
7633
/************************************************************************/
7634
/*                      BuildLayerFromSelectInfo()                      */
7635
/************************************************************************/
7636
7637
struct GDALSQLParseInfo
7638
{
7639
    swq_field_list sFieldList;
7640
    int nExtraDSCount;
7641
    GDALDataset **papoExtraDS;
7642
    char *pszWHERE;
7643
};
7644
7645
OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7646
    swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7647
    const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7648
0
{
7649
0
    std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7650
7651
0
    std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7652
0
    GDALSQLParseInfo *psParseInfo =
7653
0
        BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7654
7655
0
    if (psParseInfo)
7656
0
    {
7657
0
        const auto nErrorCounter = CPLGetErrorCounter();
7658
0
        poResults = std::make_unique<OGRGenSQLResultsLayer>(
7659
0
            this, std::move(psSelectInfoUnique), poSpatialFilter,
7660
0
            psParseInfo->pszWHERE, pszDialect);
7661
0
        if (CPLGetErrorCounter() > nErrorCounter &&
7662
0
            CPLGetLastErrorType() != CE_None)
7663
0
            poResults.reset();
7664
0
    }
7665
7666
0
    DestroyParseInfo(psParseInfo);
7667
7668
0
    return poResults.release();
7669
0
}
7670
7671
/************************************************************************/
7672
/*                          DestroyParseInfo()                          */
7673
/************************************************************************/
7674
7675
//! @cond Doxygen_Suppress
7676
void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7677
0
{
7678
0
    if (psParseInfo == nullptr)
7679
0
        return;
7680
7681
0
    CPLFree(psParseInfo->sFieldList.names);
7682
0
    CPLFree(psParseInfo->sFieldList.types);
7683
0
    CPLFree(psParseInfo->sFieldList.table_ids);
7684
0
    CPLFree(psParseInfo->sFieldList.ids);
7685
7686
    // Release the datasets we have opened with OGROpenShared()
7687
    // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7688
    // has taken a reference on them, which it will release in its
7689
    // destructor.
7690
0
    for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7691
0
        GDALClose(psParseInfo->papoExtraDS[iEDS]);
7692
7693
0
    CPLFree(psParseInfo->papoExtraDS);
7694
0
    CPLFree(psParseInfo->pszWHERE);
7695
0
    CPLFree(psParseInfo);
7696
0
}
7697
7698
/************************************************************************/
7699
/*                           BuildParseInfo()                           */
7700
/************************************************************************/
7701
7702
GDALSQLParseInfo *
7703
GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7704
                            swq_select_parse_options *poSelectParseOptions)
7705
0
{
7706
0
    int nFirstLayerFirstSpecialFieldIndex = 0;
7707
7708
0
    GDALSQLParseInfo *psParseInfo =
7709
0
        static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7710
7711
    /* -------------------------------------------------------------------- */
7712
    /*      Validate that all the source tables are recognized, count       */
7713
    /*      fields.                                                         */
7714
    /* -------------------------------------------------------------------- */
7715
0
    int nFieldCount = 0;
7716
7717
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7718
0
    {
7719
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7720
0
        GDALDataset *poTableDS = this;
7721
7722
0
        if (psTableDef->data_source != nullptr)
7723
0
        {
7724
0
            poTableDS = GDALDataset::FromHandle(
7725
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7726
0
            if (poTableDS == nullptr)
7727
0
            {
7728
0
                if (strlen(CPLGetLastErrorMsg()) == 0)
7729
0
                    CPLError(CE_Failure, CPLE_AppDefined,
7730
0
                             "Unable to open secondary datasource "
7731
0
                             "`%s' required by JOIN.",
7732
0
                             psTableDef->data_source);
7733
7734
0
                DestroyParseInfo(psParseInfo);
7735
0
                return nullptr;
7736
0
            }
7737
7738
            // Keep in an array to release at the end of this function.
7739
0
            psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7740
0
                psParseInfo->papoExtraDS,
7741
0
                sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7742
0
            psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7743
0
        }
7744
7745
0
        OGRLayer *poSrcLayer =
7746
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7747
7748
0
        if (poSrcLayer == nullptr)
7749
0
        {
7750
0
            CPLError(CE_Failure, CPLE_AppDefined,
7751
0
                     "SELECT from table %s failed, no such table/featureclass.",
7752
0
                     psTableDef->table_name);
7753
7754
0
            DestroyParseInfo(psParseInfo);
7755
0
            return nullptr;
7756
0
        }
7757
7758
0
        nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7759
0
        if (iTable == 0 ||
7760
0
            (poSelectParseOptions &&
7761
0
             poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7762
0
            nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7763
7764
0
        const char *pszFID = poSrcLayer->GetFIDColumn();
7765
0
        if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7766
0
            poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7767
0
            nFieldCount++;
7768
0
    }
7769
7770
    /* -------------------------------------------------------------------- */
7771
    /*      Build the field list for all indicated tables.                  */
7772
    /* -------------------------------------------------------------------- */
7773
7774
0
    psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7775
0
    psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7776
7777
0
    psParseInfo->sFieldList.count = 0;
7778
0
    psParseInfo->sFieldList.names = static_cast<char **>(
7779
0
        CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7780
0
    psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7781
0
        sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7782
0
    psParseInfo->sFieldList.table_ids = static_cast<int *>(
7783
0
        CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7784
0
    psParseInfo->sFieldList.ids = static_cast<int *>(
7785
0
        CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7786
7787
0
    bool bIsFID64 = false;
7788
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7789
0
    {
7790
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7791
0
        GDALDataset *poTableDS = this;
7792
7793
0
        if (psTableDef->data_source != nullptr)
7794
0
        {
7795
0
            poTableDS = GDALDataset::FromHandle(
7796
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7797
0
            CPLAssert(poTableDS != nullptr);
7798
0
            poTableDS->Dereference();
7799
0
        }
7800
7801
0
        OGRLayer *poSrcLayer =
7802
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7803
7804
0
        for (int iField = 0;
7805
0
             iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7806
0
        {
7807
0
            OGRFieldDefn *poFDefn =
7808
0
                poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7809
0
            const int iOutField = psParseInfo->sFieldList.count++;
7810
0
            psParseInfo->sFieldList.names[iOutField] =
7811
0
                const_cast<char *>(poFDefn->GetNameRef());
7812
0
            if (poFDefn->GetType() == OFTInteger)
7813
0
            {
7814
0
                if (poFDefn->GetSubType() == OFSTBoolean)
7815
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7816
0
                else
7817
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7818
0
            }
7819
0
            else if (poFDefn->GetType() == OFTInteger64)
7820
0
            {
7821
0
                if (poFDefn->GetSubType() == OFSTBoolean)
7822
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7823
0
                else
7824
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7825
0
            }
7826
0
            else if (poFDefn->GetType() == OFTReal)
7827
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7828
0
            else if (poFDefn->GetType() == OFTString)
7829
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7830
0
            else if (poFDefn->GetType() == OFTTime)
7831
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7832
0
            else if (poFDefn->GetType() == OFTDate)
7833
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7834
0
            else if (poFDefn->GetType() == OFTDateTime)
7835
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7836
0
            else
7837
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7838
7839
0
            psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7840
0
            psParseInfo->sFieldList.ids[iOutField] = iField;
7841
0
        }
7842
7843
0
        if (iTable == 0)
7844
0
        {
7845
0
            nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7846
0
        }
7847
7848
0
        if (iTable == 0 ||
7849
0
            (poSelectParseOptions &&
7850
0
             poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7851
0
        {
7852
7853
0
            for (int iField = 0;
7854
0
                 iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7855
0
                 iField++)
7856
0
            {
7857
0
                OGRGeomFieldDefn *poFDefn =
7858
0
                    poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7859
0
                const int iOutField = psParseInfo->sFieldList.count++;
7860
0
                psParseInfo->sFieldList.names[iOutField] =
7861
0
                    const_cast<char *>(poFDefn->GetNameRef());
7862
0
                if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7863
0
                    psParseInfo->sFieldList.names[iOutField] =
7864
0
                        const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7865
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7866
7867
0
                psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7868
0
                psParseInfo->sFieldList.ids[iOutField] =
7869
0
                    GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7870
0
                        poSrcLayer->GetLayerDefn(), iField);
7871
0
            }
7872
0
        }
7873
7874
0
        if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7875
0
            EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7876
0
        {
7877
0
            bIsFID64 = true;
7878
0
        }
7879
0
    }
7880
7881
    /* -------------------------------------------------------------------- */
7882
    /*      Expand '*' in 'SELECT *' now before we add the pseudo fields    */
7883
    /* -------------------------------------------------------------------- */
7884
0
    const bool bAlwaysPrefixWithTableName =
7885
0
        poSelectParseOptions &&
7886
0
        poSelectParseOptions->bAlwaysPrefixWithTableName;
7887
0
    if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7888
0
                                      bAlwaysPrefixWithTableName) != CE_None)
7889
0
    {
7890
0
        DestroyParseInfo(psParseInfo);
7891
0
        return nullptr;
7892
0
    }
7893
7894
0
    for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7895
0
    {
7896
0
        psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7897
0
            const_cast<char *>(SpecialFieldNames[iField]);
7898
0
        psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7899
0
            (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7900
0
                                            : SpecialFieldTypes[iField];
7901
0
        psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7902
0
        psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7903
0
            nFirstLayerFirstSpecialFieldIndex + iField;
7904
0
        psParseInfo->sFieldList.count++;
7905
0
    }
7906
7907
    /* In the case a layer has an explicit FID column name, then add it */
7908
    /* so it can be selected */
7909
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7910
0
    {
7911
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7912
0
        GDALDataset *poTableDS = this;
7913
7914
0
        if (psTableDef->data_source != nullptr)
7915
0
        {
7916
0
            poTableDS = GDALDataset::FromHandle(
7917
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7918
0
            CPLAssert(poTableDS != nullptr);
7919
0
            poTableDS->Dereference();
7920
0
        }
7921
7922
0
        OGRLayer *poSrcLayer =
7923
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7924
7925
0
        const char *pszFID = poSrcLayer->GetFIDColumn();
7926
0
        if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7927
0
            poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7928
0
        {
7929
0
            const int iOutField = psParseInfo->sFieldList.count++;
7930
0
            psParseInfo->sFieldList.names[iOutField] =
7931
0
                const_cast<char *>(pszFID);
7932
0
            if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7933
0
                EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7934
0
            {
7935
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7936
0
            }
7937
0
            else
7938
0
            {
7939
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7940
0
            }
7941
0
            psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7942
0
            psParseInfo->sFieldList.ids[iOutField] =
7943
0
                poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7944
0
        }
7945
0
    }
7946
7947
    /* -------------------------------------------------------------------- */
7948
    /*      Finish the parse operation.                                     */
7949
    /* -------------------------------------------------------------------- */
7950
0
    if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7951
0
        CE_None)
7952
0
    {
7953
0
        DestroyParseInfo(psParseInfo);
7954
0
        return nullptr;
7955
0
    }
7956
7957
    /* -------------------------------------------------------------------- */
7958
    /*      Extract the WHERE expression to use separately.                 */
7959
    /* -------------------------------------------------------------------- */
7960
0
    if (psSelectInfo->where_expr != nullptr)
7961
0
    {
7962
0
        psParseInfo->pszWHERE =
7963
0
            psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7964
        // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7965
0
    }
7966
7967
0
    return psParseInfo;
7968
0
}
7969
7970
//! @endcond
7971
7972
/************************************************************************/
7973
/*                          ReleaseResultSet()                          */
7974
/************************************************************************/
7975
7976
/**
7977
 \brief Release results of ExecuteSQL().
7978
7979
 This method should only be used to deallocate OGRLayers resulting from
7980
 an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
7981
 results set before destroying the GDALDataset may cause errors.
7982
7983
 This method is the same as the C function GDALDatasetReleaseResultSet() and the
7984
 deprecated OGR_DS_ReleaseResultSet().
7985
7986
 @param poResultsSet the result of a previous ExecuteSQL() call.
7987
*/
7988
7989
void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7990
7991
0
{
7992
0
    delete poResultsSet;
7993
0
}
7994
7995
/************************************************************************/
7996
/*                           GetStyleTable()                            */
7997
/************************************************************************/
7998
7999
/**
8000
 \brief Returns dataset style table.
8001
8002
 This method is the same as the C function GDALDatasetGetStyleTable() and the
8003
 deprecated OGR_DS_GetStyleTable().
8004
8005
 @return pointer to a style table which should not be modified or freed by the
8006
 caller.
8007
*/
8008
8009
OGRStyleTable *GDALDataset::GetStyleTable()
8010
0
{
8011
0
    return m_poStyleTable;
8012
0
}
8013
8014
/************************************************************************/
8015
/*                       SetStyleTableDirectly()                        */
8016
/************************************************************************/
8017
8018
/**
8019
 \brief Set dataset style table.
8020
8021
 This method operate exactly as SetStyleTable() except that it
8022
 assumes ownership of the passed table.
8023
8024
 This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8025
 and the deprecated OGR_DS_SetStyleTableDirectly().
8026
8027
 @param poStyleTable pointer to style table to set
8028
8029
*/
8030
void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8031
0
{
8032
0
    if (m_poStyleTable)
8033
0
        delete m_poStyleTable;
8034
0
    m_poStyleTable = poStyleTable;
8035
0
}
8036
8037
/************************************************************************/
8038
/*                           SetStyleTable()                            */
8039
/************************************************************************/
8040
8041
/**
8042
 \brief Set dataset style table.
8043
8044
 This method operate exactly as SetStyleTableDirectly() except
8045
 that it does not assume ownership of the passed table.
8046
8047
 This method is the same as the C function GDALDatasetSetStyleTable() and the
8048
 deprecated OGR_DS_SetStyleTable().
8049
8050
 @param poStyleTable pointer to style table to set
8051
8052
*/
8053
8054
void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8055
0
{
8056
0
    if (m_poStyleTable)
8057
0
        delete m_poStyleTable;
8058
0
    if (poStyleTable)
8059
0
        m_poStyleTable = poStyleTable->Clone();
8060
0
}
8061
8062
/************************************************************************/
8063
/*                        IsGenericSQLDialect()                         */
8064
/************************************************************************/
8065
8066
//! @cond Doxygen_Suppress
8067
int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8068
0
{
8069
0
    return pszDialect != nullptr &&
8070
0
           (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8071
0
}
8072
8073
//! @endcond
8074
8075
/************************************************************************/
8076
/*                           GetLayerCount()                            */
8077
/************************************************************************/
8078
8079
/**
8080
 \brief Get the number of layers in this dataset.
8081
8082
 This method is the same as the C function GDALDatasetGetLayerCount(),
8083
 and the deprecated OGR_DS_GetLayerCount().
8084
8085
 Note that even if this method is const, there is no guarantee it can be
8086
 safely called by concurrent threads on the same GDALDataset object.
8087
8088
 @return layer count.
8089
*/
8090
8091
int GDALDataset::GetLayerCount() const
8092
0
{
8093
0
    return 0;
8094
0
}
8095
8096
/************************************************************************/
8097
/*                              GetLayer()                              */
8098
/************************************************************************/
8099
8100
/**
8101
 \fn const GDALDataset::GetLayer(int) const
8102
 \brief Fetch a layer by index.
8103
8104
 The returned layer remains owned by the
8105
 GDALDataset and should not be deleted by the application.
8106
8107
 Note that even if this method is const, there is no guarantee it can be
8108
 safely called by concurrent threads on the same GDALDataset object.
8109
8110
 See GetLayers() for a C++ iterator version of this method.
8111
8112
 This method is the same as the C function GDALDatasetGetLayer() and the
8113
 deprecated OGR_DS_GetLayer().
8114
8115
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8116
8117
 @return the layer, or NULL if iLayer is out of range or an error occurs.
8118
8119
 @see GetLayers()
8120
8121
 @since GDAL 3.12
8122
*/
8123
8124
const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8125
0
{
8126
0
    return nullptr;
8127
0
}
8128
8129
/**
8130
 \fn GDALDataset::GetLayer(int)
8131
 \brief Fetch a layer by index.
8132
8133
 The returned layer remains owned by the
8134
 GDALDataset and should not be deleted by the application.
8135
8136
 See GetLayers() for a C++ iterator version of this method.
8137
8138
 This method is the same as the C function GDALDatasetGetLayer() and the
8139
 deprecated OGR_DS_GetLayer().
8140
8141
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8142
8143
 @return the layer, or NULL if iLayer is out of range or an error occurs.
8144
8145
 @see GetLayers()
8146
*/
8147
8148
/************************************************************************/
8149
/*                           IsLayerPrivate()                           */
8150
/************************************************************************/
8151
8152
/**
8153
 \fn GDALDataset::IsLayerPrivate(int)
8154
 \brief Returns true if the layer at the specified index is deemed a private or
8155
 system table, or an internal detail only.
8156
8157
 This method is the same as the C function GDALDatasetIsLayerPrivate().
8158
8159
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8160
8161
 @return true if the layer is a private or system table.
8162
8163
 @since GDAL 3.4
8164
*/
8165
8166
bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8167
0
{
8168
0
    return false;
8169
0
}
8170
8171
/************************************************************************/
8172
/*                            ResetReading()                            */
8173
/************************************************************************/
8174
8175
/**
8176
 \brief Reset feature reading to start on the first feature.
8177
8178
 This affects GetNextFeature().
8179
8180
 Depending on drivers, this may also have the side effect of calling
8181
 OGRLayer::ResetReading() on the layers of this dataset.
8182
8183
 This method is the same as the C function GDALDatasetResetReading().
8184
8185
*/
8186
void GDALDataset::ResetReading()
8187
0
{
8188
0
    if (!m_poPrivate)
8189
0
        return;
8190
0
    m_poPrivate->nCurrentLayerIdx = 0;
8191
0
    m_poPrivate->nLayerCount = -1;
8192
0
    m_poPrivate->poCurrentLayer = nullptr;
8193
0
    m_poPrivate->nFeatureReadInLayer = 0;
8194
0
    m_poPrivate->nFeatureReadInDataset = 0;
8195
0
    m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8196
0
    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8197
0
}
8198
8199
/************************************************************************/
8200
/*                      GDALDatasetResetReading()                       */
8201
/************************************************************************/
8202
8203
/**
8204
 \brief Reset feature reading to start on the first feature.
8205
8206
 This affects GDALDatasetGetNextFeature().
8207
8208
 Depending on drivers, this may also have the side effect of calling
8209
 OGR_L_ResetReading() on the layers of this dataset.
8210
8211
 This method is the same as the C++ method GDALDataset::ResetReading()
8212
8213
 @param hDS dataset handle
8214
*/
8215
void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8216
0
{
8217
0
    VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8218
8219
0
    return GDALDataset::FromHandle(hDS)->ResetReading();
8220
0
}
8221
8222
/************************************************************************/
8223
/*                           GetNextFeature()                           */
8224
/************************************************************************/
8225
8226
/**
8227
 \brief Fetch the next available feature from this dataset.
8228
8229
 This method is intended for the few drivers where OGRLayer::GetNextFeature()
8230
 is not efficient, but in general OGRLayer::GetNextFeature() is a more
8231
 natural API.
8232
8233
 See GetFeatures() for a C++ iterator version of this method.
8234
8235
 The returned feature becomes the responsibility of the caller to
8236
 delete with OGRFeature::DestroyFeature().
8237
8238
 Depending on the driver, this method may return features from layers in a
8239
 non sequential way. This is what may happen when the
8240
 ODsCRandomLayerRead capability is declared (for example for the
8241
 OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8242
 advised to use GDALDataset::GetNextFeature() instead of
8243
 OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8244
 implementation.
8245
8246
 The default implementation, used by most drivers, will
8247
 however iterate over each layer, and then over each feature within this
8248
 layer.
8249
8250
 This method takes into account spatial and attribute filters set on layers that
8251
 will be iterated upon.
8252
8253
 The ResetReading() method can be used to start at the beginning again.
8254
8255
 Depending on drivers, this may also have the side effect of calling
8256
 OGRLayer::GetNextFeature() on the layers of this dataset.
8257
8258
 This method is the same as the C function GDALDatasetGetNextFeature().
8259
8260
 @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8261
                          layer to which the object belongs to, or NULL.
8262
                          It is possible that the output of *ppoBelongingLayer
8263
                          to be NULL despite the feature not being NULL.
8264
 @param pdfProgressPct    a pointer to a double variable to receive the
8265
                          percentage progress (in [0,1] range), or NULL.
8266
                          On return, the pointed value might be negative if
8267
                          determining the progress is not possible.
8268
 @param pfnProgress       a progress callback to report progress (for
8269
                          GetNextFeature() calls that might have a long
8270
                          duration) and offer cancellation possibility, or NULL.
8271
 @param pProgressData     user data provided to pfnProgress, or NULL
8272
 @return a feature, or NULL if no more features are available.
8273
 @see GetFeatures()
8274
*/
8275
8276
OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8277
                                        double *pdfProgressPct,
8278
                                        GDALProgressFunc pfnProgress,
8279
                                        void *pProgressData)
8280
0
{
8281
0
    if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8282
0
    {
8283
0
        if (ppoBelongingLayer != nullptr)
8284
0
            *ppoBelongingLayer = nullptr;
8285
0
        if (pdfProgressPct != nullptr)
8286
0
            *pdfProgressPct = 1.0;
8287
0
        if (pfnProgress != nullptr)
8288
0
            pfnProgress(1.0, "", pProgressData);
8289
0
        return nullptr;
8290
0
    }
8291
8292
0
    if (m_poPrivate->poCurrentLayer == nullptr &&
8293
0
        (pdfProgressPct != nullptr || pfnProgress != nullptr))
8294
0
    {
8295
0
        if (m_poPrivate->nLayerCount < 0)
8296
0
        {
8297
0
            m_poPrivate->nLayerCount = GetLayerCount();
8298
0
        }
8299
8300
0
        if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8301
0
        {
8302
0
            m_poPrivate->nTotalFeatures = 0;
8303
0
            for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8304
0
            {
8305
0
                OGRLayer *poLayer = GetLayer(i);
8306
0
                if (poLayer == nullptr ||
8307
0
                    !poLayer->TestCapability(OLCFastFeatureCount))
8308
0
                {
8309
0
                    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8310
0
                    break;
8311
0
                }
8312
0
                GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8313
0
                if (nCount < 0)
8314
0
                {
8315
0
                    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8316
0
                    break;
8317
0
                }
8318
0
                m_poPrivate->nTotalFeatures += nCount;
8319
0
            }
8320
0
        }
8321
0
    }
8322
8323
0
    while (true)
8324
0
    {
8325
0
        if (m_poPrivate->poCurrentLayer == nullptr)
8326
0
        {
8327
0
            m_poPrivate->poCurrentLayer =
8328
0
                GetLayer(m_poPrivate->nCurrentLayerIdx);
8329
0
            if (m_poPrivate->poCurrentLayer == nullptr)
8330
0
            {
8331
0
                m_poPrivate->nCurrentLayerIdx = -1;
8332
0
                if (ppoBelongingLayer != nullptr)
8333
0
                    *ppoBelongingLayer = nullptr;
8334
0
                if (pdfProgressPct != nullptr)
8335
0
                    *pdfProgressPct = 1.0;
8336
0
                return nullptr;
8337
0
            }
8338
0
            m_poPrivate->poCurrentLayer->ResetReading();
8339
0
            m_poPrivate->nFeatureReadInLayer = 0;
8340
0
            if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8341
0
            {
8342
0
                if (m_poPrivate->poCurrentLayer->TestCapability(
8343
0
                        OLCFastFeatureCount))
8344
0
                    m_poPrivate->nTotalFeaturesInLayer =
8345
0
                        m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8346
0
                else
8347
0
                    m_poPrivate->nTotalFeaturesInLayer = 0;
8348
0
            }
8349
0
        }
8350
0
        OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8351
0
        if (poFeature == nullptr)
8352
0
        {
8353
0
            m_poPrivate->nCurrentLayerIdx++;
8354
0
            m_poPrivate->poCurrentLayer = nullptr;
8355
0
            continue;
8356
0
        }
8357
8358
0
        m_poPrivate->nFeatureReadInLayer++;
8359
0
        m_poPrivate->nFeatureReadInDataset++;
8360
0
        if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8361
0
        {
8362
0
            double dfPct = 0.0;
8363
0
            if (m_poPrivate->nTotalFeatures > 0)
8364
0
            {
8365
0
                dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8366
0
                        m_poPrivate->nTotalFeatures;
8367
0
            }
8368
0
            else
8369
0
            {
8370
0
                dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8371
0
                        m_poPrivate->nLayerCount;
8372
0
                if (m_poPrivate->nTotalFeaturesInLayer > 0)
8373
0
                {
8374
0
                    dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8375
0
                             m_poPrivate->nTotalFeaturesInLayer /
8376
0
                             m_poPrivate->nLayerCount;
8377
0
                }
8378
0
            }
8379
0
            if (pdfProgressPct)
8380
0
                *pdfProgressPct = dfPct;
8381
0
            if (pfnProgress)
8382
0
                pfnProgress(dfPct, "", nullptr);
8383
0
        }
8384
8385
0
        if (ppoBelongingLayer != nullptr)
8386
0
            *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8387
0
        return poFeature;
8388
0
    }
8389
0
}
8390
8391
/************************************************************************/
8392
/*                     GDALDatasetGetNextFeature()                      */
8393
/************************************************************************/
8394
/**
8395
 \brief Fetch the next available feature from this dataset.
8396
8397
 This method is intended for the few drivers where OGR_L_GetNextFeature()
8398
 is not efficient, but in general OGR_L_GetNextFeature() is a more
8399
 natural API.
8400
8401
 The returned feature becomes the responsibility of the caller to
8402
 delete with OGRFeature::DestroyFeature().
8403
8404
 Depending on the driver, this method may return features from layers in a
8405
 non sequential way. This is what may happen when the
8406
 ODsCRandomLayerRead capability is declared (for example for the
8407
 OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8408
 advised to use GDALDataset::GetNextFeature() instead of
8409
 OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8410
 implementation.
8411
8412
 The default implementation, used by most drivers, will
8413
 however iterate over each layer, and then over each feature within this
8414
 layer.
8415
8416
 This method takes into account spatial and attribute filters set on layers that
8417
 will be iterated upon.
8418
8419
 The ResetReading() method can be used to start at the beginning again.
8420
8421
 Depending on drivers, this may also have the side effect of calling
8422
 OGRLayer::GetNextFeature() on the layers of this dataset.
8423
8424
 This method is the same as the C++ method GDALDataset::GetNextFeature()
8425
8426
 @param hDS               dataset handle.
8427
 @param phBelongingLayer  a pointer to a OGRLayer* variable to receive the
8428
                          layer to which the object belongs to, or NULL.
8429
                          It is possible that the output of *ppoBelongingLayer
8430
                          to be NULL despite the feature not being NULL.
8431
 @param pdfProgressPct    a pointer to a double variable to receive the
8432
                          percentage progress (in [0,1] range), or NULL.
8433
                          On return, the pointed value might be negative if
8434
                          determining the progress is not possible.
8435
 @param pfnProgress       a progress callback to report progress (for
8436
                          GetNextFeature() calls that might have a long
8437
                          duration) and offer cancellation possibility, or NULL
8438
 @param pProgressData     user data provided to pfnProgress, or NULL
8439
 @return a feature, or NULL if no more features are available.
8440
*/
8441
OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8442
                                              OGRLayerH *phBelongingLayer,
8443
                                              double *pdfProgressPct,
8444
                                              GDALProgressFunc pfnProgress,
8445
                                              void *pProgressData)
8446
0
{
8447
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8448
8449
0
    return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8450
0
        reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8451
0
        pfnProgress, pProgressData));
8452
0
}
8453
8454
/************************************************************************/
8455
/*                           TestCapability()                           */
8456
/************************************************************************/
8457
8458
/**
8459
 \fn GDALDataset::TestCapability( const char * pszCap )
8460
 \brief Test if capability is available.
8461
8462
 One of the following dataset capability names can be passed into this
8463
 method, and a TRUE or FALSE value will be returned indicating whether or not
8464
 the capability is available for this object.
8465
8466
 <ul>
8467
  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8468
  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8469
          layers.<p>
8470
  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8471
          datasource support CreateGeomField() just after layer creation.<p>
8472
  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8473
          geometries.<p>
8474
  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8475
          transactions.<p>
8476
  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8477
          transactions through emulation.<p>
8478
  <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8479
          GetNextFeature() implementation, potentially returning features from
8480
          layers in a non sequential way.<p>
8481
  <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8482
         CreateFeature() on layers in a non sequential way.<p>
8483
  <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8484
  <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8485
  <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8486
  <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8487
  <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8488
 </ul>
8489
8490
 The \#define macro forms of the capability names should be used in preference
8491
 to the strings themselves to avoid misspelling.
8492
8493
 This method is the same as the C function GDALDatasetTestCapability() and the
8494
 deprecated OGR_DS_TestCapability().
8495
8496
 @param pszCap the capability to test.
8497
8498
 @return TRUE if capability available otherwise FALSE.
8499
*/
8500
8501
int GDALDataset::TestCapability(const char *pszCap) const
8502
0
{
8503
0
    if (EQUAL(pszCap, GDsCFastGetExtent) ||
8504
0
        EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8505
0
    {
8506
0
        for (auto &&poLayer : GetLayers())
8507
0
        {
8508
0
            if (!poLayer->TestCapability(OLCFastGetExtent))
8509
0
                return FALSE;
8510
0
        }
8511
0
        return TRUE;
8512
0
    }
8513
0
    return FALSE;
8514
0
}
8515
8516
/************************************************************************/
8517
/*                     GDALDatasetTestCapability()                      */
8518
/************************************************************************/
8519
8520
/**
8521
 \brief Test if capability is available.
8522
8523
 One of the following dataset capability names can be passed into this
8524
 function, and a TRUE or FALSE value will be returned indicating whether or not
8525
 the capability is available for this object.
8526
8527
 <ul>
8528
  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8529
  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8530
          layers.<p>
8531
  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8532
          datasource support CreateGeomField() just after layer creation.<p>
8533
  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8534
          geometries.<p>
8535
  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8536
          transactions.<p>
8537
  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8538
          transactions through emulation.<p>
8539
  <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8540
          GetNextFeature() implementation, potentially returning features from
8541
          layers in a non sequential way.<p>
8542
  <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8543
          CreateFeature() on layers in a non sequential way.<p>
8544
  <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8545
  <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8546
  <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8547
  <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8548
  <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8549
 </ul>
8550
8551
 The \#define macro forms of the capability names should be used in preference
8552
 to the strings themselves to avoid misspelling.
8553
8554
 This function is the same as the C++ method GDALDataset::TestCapability()
8555
8556
8557
 @param hDS the dataset handle.
8558
 @param pszCap the capability to test.
8559
8560
 @return TRUE if capability available otherwise FALSE.
8561
*/
8562
int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8563
8564
0
{
8565
0
    VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8566
0
    VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8567
8568
0
    return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8569
0
}
8570
8571
/************************************************************************/
8572
/*                          StartTransaction()                          */
8573
/************************************************************************/
8574
8575
/**
8576
 \fn GDALDataset::StartTransaction(int)
8577
 \brief For datasources which support transactions, StartTransaction creates a
8578
`transaction.
8579
8580
 If starting the transaction fails, will return
8581
 OGRERR_FAILURE. Datasources which do not support transactions will
8582
 always return OGRERR_UNSUPPORTED_OPERATION.
8583
8584
 Nested transactions are not supported.
8585
8586
 All changes done after the start of the transaction are definitely applied in
8587
 the datasource if CommitTransaction() is called. They may be canceled by
8588
 calling RollbackTransaction() instead.
8589
8590
 At the time of writing, transactions only apply on vector layers.
8591
8592
 Datasets that support transactions will advertise the ODsCTransactions
8593
 capability.  Use of transactions at dataset level is generally preferred to
8594
 transactions at layer level, whose scope is rarely limited to the layer from
8595
 which it was started.
8596
8597
 In case StartTransaction() fails, neither CommitTransaction() or
8598
 RollbackTransaction() should be called.
8599
8600
 If an error occurs after a successful StartTransaction(), the whole transaction
8601
 may or may not be implicitly canceled, depending on drivers. (e.g.  the PG
8602
 driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8603
 an explicit call to RollbackTransaction() should be done to keep things
8604
 balanced.
8605
8606
 By default, when bForce is set to FALSE, only "efficient" transactions will be
8607
 attempted. Some drivers may offer an emulation of transactions, but sometimes
8608
 with significant overhead, in which case the user must explicitly allow for
8609
 such an emulation by setting bForce to TRUE. Drivers that offer emulated
8610
 transactions should advertise the ODsCEmulatedTransactions capability (and not
8611
 ODsCTransactions).
8612
8613
 This function is the same as the C function GDALDatasetStartTransaction().
8614
8615
 @param bForce can be set to TRUE if an emulation, possibly slow, of a
8616
 transaction
8617
               mechanism is acceptable.
8618
8619
 @return OGRERR_NONE on success.
8620
*/
8621
8622
OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8623
0
{
8624
0
    return OGRERR_UNSUPPORTED_OPERATION;
8625
0
}
8626
8627
/************************************************************************/
8628
/*                    GDALDatasetStartTransaction()                     */
8629
/************************************************************************/
8630
8631
/**
8632
 \brief For datasources which support transactions, StartTransaction creates a
8633
 transaction.
8634
8635
 If starting the transaction fails, will return
8636
 OGRERR_FAILURE. Datasources which do not support transactions will
8637
 always return OGRERR_UNSUPPORTED_OPERATION.
8638
8639
 Nested transactions are not supported.
8640
8641
 All changes done after the start of the transaction are definitely applied in
8642
 the datasource if CommitTransaction() is called. They may be canceled by
8643
 calling RollbackTransaction() instead.
8644
8645
 At the time of writing, transactions only apply on vector layers.
8646
8647
 Datasets that support transactions will advertise the ODsCTransactions
8648
 capability.
8649
 Use of transactions at dataset level is generally preferred to transactions at
8650
 layer level, whose scope is rarely limited to the layer from which it was
8651
 started.
8652
8653
 In case StartTransaction() fails, neither CommitTransaction() or
8654
 RollbackTransaction() should be called.
8655
8656
 If an error occurs after a successful StartTransaction(), the whole
8657
 transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8658
 the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8659
 error, an explicit call to RollbackTransaction() should be done to keep things
8660
 balanced.
8661
8662
 By default, when bForce is set to FALSE, only "efficient" transactions will be
8663
 attempted. Some drivers may offer an emulation of transactions, but sometimes
8664
 with significant overhead, in which case the user must explicitly allow for
8665
 such an emulation by setting bForce to TRUE. Drivers that offer emulated
8666
 transactions should advertise the ODsCEmulatedTransactions capability (and not
8667
 ODsCTransactions).
8668
8669
 This function is the same as the C++ method GDALDataset::StartTransaction()
8670
8671
 @param hDS the dataset handle.
8672
 @param bForce can be set to TRUE if an emulation, possibly slow, of a
8673
 transaction
8674
               mechanism is acceptable.
8675
8676
 @return OGRERR_NONE on success.
8677
*/
8678
OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8679
0
{
8680
0
    VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8681
0
                      OGRERR_INVALID_HANDLE);
8682
8683
0
#ifdef OGRAPISPY_ENABLED
8684
0
    if (bOGRAPISpyEnabled)
8685
0
        OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8686
0
#endif
8687
8688
0
    return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8689
0
}
8690
8691
/************************************************************************/
8692
/*                         CommitTransaction()                          */
8693
/************************************************************************/
8694
8695
/**
8696
 \brief For datasources which support transactions, CommitTransaction commits a
8697
 transaction.
8698
8699
 If no transaction is active, or the commit fails, will return
8700
 OGRERR_FAILURE. Datasources which do not support transactions will
8701
 always return OGRERR_UNSUPPORTED_OPERATION.
8702
8703
 Depending on drivers, this may or may not abort layer sequential readings that
8704
 are active.
8705
8706
 This function is the same as the C function GDALDatasetCommitTransaction().
8707
8708
 @return OGRERR_NONE on success.
8709
*/
8710
OGRErr GDALDataset::CommitTransaction()
8711
0
{
8712
0
    return OGRERR_UNSUPPORTED_OPERATION;
8713
0
}
8714
8715
/************************************************************************/
8716
/*                    GDALDatasetCommitTransaction()                    */
8717
/************************************************************************/
8718
8719
/**
8720
 \brief For datasources which support transactions, CommitTransaction commits a
8721
 transaction.
8722
8723
 If no transaction is active, or the commit fails, will return
8724
 OGRERR_FAILURE. Datasources which do not support transactions will
8725
 always return OGRERR_UNSUPPORTED_OPERATION.
8726
8727
 Depending on drivers, this may or may not abort layer sequential readings that
8728
 are active.
8729
8730
 This function is the same as the C++ method GDALDataset::CommitTransaction()
8731
8732
 @return OGRERR_NONE on success.
8733
*/
8734
OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8735
0
{
8736
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8737
0
                      OGRERR_INVALID_HANDLE);
8738
8739
0
#ifdef OGRAPISPY_ENABLED
8740
0
    if (bOGRAPISpyEnabled)
8741
0
        OGRAPISpy_Dataset_CommitTransaction(hDS);
8742
0
#endif
8743
8744
0
    return GDALDataset::FromHandle(hDS)->CommitTransaction();
8745
0
}
8746
8747
/************************************************************************/
8748
/*                        RollbackTransaction()                         */
8749
/************************************************************************/
8750
8751
/**
8752
 \brief For datasources which support transactions, RollbackTransaction will
8753
 roll back a datasource to its state before the start of the current
8754
 transaction.
8755
 If no transaction is active, or the rollback fails, will return
8756
 OGRERR_FAILURE. Datasources which do not support transactions will
8757
 always return OGRERR_UNSUPPORTED_OPERATION.
8758
8759
 This function is the same as the C function GDALDatasetRollbackTransaction().
8760
8761
 @return OGRERR_NONE on success.
8762
*/
8763
OGRErr GDALDataset::RollbackTransaction()
8764
0
{
8765
0
    return OGRERR_UNSUPPORTED_OPERATION;
8766
0
}
8767
8768
/************************************************************************/
8769
/*                   GDALDatasetRollbackTransaction()                   */
8770
/************************************************************************/
8771
8772
/**
8773
 \brief For datasources which support transactions, RollbackTransaction will
8774
 roll back a datasource to its state before the start of the current
8775
 transaction.
8776
 If no transaction is active, or the rollback fails, will return
8777
 OGRERR_FAILURE. Datasources which do not support transactions will
8778
 always return OGRERR_UNSUPPORTED_OPERATION.
8779
8780
 This function is the same as the C++ method GDALDataset::RollbackTransaction().
8781
8782
 @return OGRERR_NONE on success.
8783
*/
8784
OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8785
0
{
8786
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8787
0
                      OGRERR_INVALID_HANDLE);
8788
8789
0
#ifdef OGRAPISPY_ENABLED
8790
0
    if (bOGRAPISpyEnabled)
8791
0
        OGRAPISpy_Dataset_RollbackTransaction(hDS);
8792
0
#endif
8793
8794
0
    return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8795
0
}
8796
8797
//! @cond Doxygen_Suppress
8798
8799
/************************************************************************/
8800
/*                     ShareLockWithParentDataset()                     */
8801
/************************************************************************/
8802
8803
/* To be used typically by the GTiff driver to link overview datasets */
8804
/* with their main dataset, so that they share the same lock */
8805
/* Cf https://github.com/OSGeo/gdal/issues/1488 */
8806
/* The parent dataset should remain alive while the this dataset is alive */
8807
8808
void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8809
0
{
8810
0
    if (m_poPrivate != nullptr)
8811
0
    {
8812
0
        m_poPrivate->poParentDataset = poParentDataset;
8813
0
    }
8814
0
}
8815
8816
/************************************************************************/
8817
/*                         SetQueryLoggerFunc()                         */
8818
/************************************************************************/
8819
8820
bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8821
                                     CPL_UNUSED void *context)
8822
0
{
8823
0
    return false;
8824
0
}
8825
8826
/************************************************************************/
8827
/*                           EnterReadWrite()                           */
8828
/************************************************************************/
8829
8830
int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8831
0
{
8832
0
    if (m_poPrivate == nullptr ||
8833
0
        IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8834
0
        return FALSE;
8835
8836
0
    if (m_poPrivate->poParentDataset)
8837
0
        return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8838
8839
0
    if (eAccess == GA_Update)
8840
0
    {
8841
0
        if (m_poPrivate->eStateReadWriteMutex ==
8842
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8843
0
        {
8844
            // In case dead-lock would occur, which is not impossible,
8845
            // this can be used to prevent it, but at the risk of other
8846
            // issues.
8847
0
            if (CPLTestBool(
8848
0
                    CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8849
0
            {
8850
0
                m_poPrivate->eStateReadWriteMutex =
8851
0
                    GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8852
0
            }
8853
0
            else
8854
0
            {
8855
0
                m_poPrivate->eStateReadWriteMutex =
8856
0
                    GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8857
0
            }
8858
0
        }
8859
0
        if (m_poPrivate->eStateReadWriteMutex ==
8860
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8861
0
        {
8862
            // There should be no race related to creating this mutex since
8863
            // it should be first created through IWriteBlock() / IRasterIO()
8864
            // and then GDALRasterBlock might call it from another thread.
8865
#ifdef DEBUG_VERBOSE
8866
            CPLDebug("GDAL",
8867
                     "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8868
                     CPLGetPID(), GetDescription());
8869
#endif
8870
0
            CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8871
8872
0
            const int nCountMutex =
8873
0
                m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8874
0
            if (nCountMutex == 0 && eRWFlag == GF_Read)
8875
0
            {
8876
0
                CPLReleaseMutex(m_poPrivate->hMutex);
8877
0
                for (int i = 0; i < nBands; i++)
8878
0
                {
8879
0
                    auto blockCache = papoBands[i]->poBandBlockCache;
8880
0
                    if (blockCache)
8881
0
                        blockCache->WaitCompletionPendingTasks();
8882
0
                }
8883
0
                CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8884
0
            }
8885
8886
0
            return TRUE;
8887
0
        }
8888
0
    }
8889
0
    return FALSE;
8890
0
}
8891
8892
/************************************************************************/
8893
/*                           LeaveReadWrite()                           */
8894
/************************************************************************/
8895
8896
void GDALDataset::LeaveReadWrite()
8897
0
{
8898
0
    if (m_poPrivate)
8899
0
    {
8900
0
        if (m_poPrivate->poParentDataset)
8901
0
        {
8902
0
            m_poPrivate->poParentDataset->LeaveReadWrite();
8903
0
            return;
8904
0
        }
8905
8906
0
        m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8907
0
        CPLReleaseMutex(m_poPrivate->hMutex);
8908
#ifdef DEBUG_VERBOSE
8909
        CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8910
                 CPLGetPID(), GetDescription());
8911
#endif
8912
0
    }
8913
0
}
8914
8915
/************************************************************************/
8916
/*                             InitRWLock()                             */
8917
/************************************************************************/
8918
8919
void GDALDataset::InitRWLock()
8920
0
{
8921
0
    if (m_poPrivate)
8922
0
    {
8923
0
        if (m_poPrivate->poParentDataset)
8924
0
        {
8925
0
            m_poPrivate->poParentDataset->InitRWLock();
8926
0
            return;
8927
0
        }
8928
8929
0
        if (m_poPrivate->eStateReadWriteMutex ==
8930
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8931
0
        {
8932
0
            if (EnterReadWrite(GF_Write))
8933
0
                LeaveReadWrite();
8934
0
        }
8935
0
    }
8936
0
}
8937
8938
/************************************************************************/
8939
/*                       DisableReadWriteMutex()                        */
8940
/************************************************************************/
8941
8942
// The mutex logic is broken in multi-threaded situations, for example
8943
// with 2 WarpedVRT datasets being read at the same time. In that
8944
// particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8945
// to disable it.
8946
void GDALDataset::DisableReadWriteMutex()
8947
0
{
8948
0
    if (m_poPrivate)
8949
0
    {
8950
0
        if (m_poPrivate->poParentDataset)
8951
0
        {
8952
0
            m_poPrivate->poParentDataset->DisableReadWriteMutex();
8953
0
            return;
8954
0
        }
8955
8956
0
        m_poPrivate->eStateReadWriteMutex =
8957
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8958
0
    }
8959
0
}
8960
8961
/************************************************************************/
8962
/*                    TemporarilyDropReadWriteLock()                    */
8963
/************************************************************************/
8964
8965
void GDALDataset::TemporarilyDropReadWriteLock()
8966
0
{
8967
0
    if (m_poPrivate == nullptr)
8968
0
        return;
8969
8970
0
    if (m_poPrivate->poParentDataset)
8971
0
    {
8972
0
        m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8973
0
        return;
8974
0
    }
8975
8976
0
#ifndef __COVERITY__
8977
0
    if (m_poPrivate->hMutex)
8978
0
    {
8979
#ifdef DEBUG_VERBOSE
8980
        CPLDebug("GDAL",
8981
                 "[Thread " CPL_FRMT_GIB "] "
8982
                 "Temporarily drop RW mutex for %s",
8983
                 CPLGetPID(), GetDescription());
8984
#endif
8985
0
        CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8986
0
        const int nCount =
8987
0
            m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8988
#ifdef DEBUG_EXTRA
8989
        m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8990
#endif
8991
0
        for (int i = 0; i < nCount + 1; i++)
8992
0
        {
8993
            // The mutex is recursive
8994
0
            CPLReleaseMutex(m_poPrivate->hMutex);
8995
0
        }
8996
0
    }
8997
0
#endif
8998
0
}
8999
9000
/************************************************************************/
9001
/*                       ReacquireReadWriteLock()                       */
9002
/************************************************************************/
9003
9004
void GDALDataset::ReacquireReadWriteLock()
9005
0
{
9006
0
    if (m_poPrivate == nullptr)
9007
0
        return;
9008
9009
0
    if (m_poPrivate->poParentDataset)
9010
0
    {
9011
0
        m_poPrivate->poParentDataset->ReacquireReadWriteLock();
9012
0
        return;
9013
0
    }
9014
9015
0
#ifndef __COVERITY__
9016
0
    if (m_poPrivate->hMutex)
9017
0
    {
9018
#ifdef DEBUG_VERBOSE
9019
        CPLDebug("GDAL",
9020
                 "[Thread " CPL_FRMT_GIB "] "
9021
                 "Reacquire temporarily dropped RW mutex for %s",
9022
                 CPLGetPID(), GetDescription());
9023
#endif
9024
0
        CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9025
0
        const int nCount =
9026
0
            m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9027
#ifdef DEBUG_EXTRA
9028
        CPLAssert(nCount ==
9029
                  m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9030
#endif
9031
0
        if (nCount == 0)
9032
0
            CPLReleaseMutex(m_poPrivate->hMutex);
9033
0
        for (int i = 0; i < nCount - 1; i++)
9034
0
        {
9035
            // The mutex is recursive
9036
0
            CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9037
0
        }
9038
0
    }
9039
0
#endif
9040
0
}
9041
9042
/************************************************************************/
9043
/*                            AcquireMutex()                            */
9044
/************************************************************************/
9045
9046
int GDALDataset::AcquireMutex()
9047
0
{
9048
0
    if (m_poPrivate == nullptr)
9049
0
        return 0;
9050
0
    if (m_poPrivate->poParentDataset)
9051
0
    {
9052
0
        return m_poPrivate->poParentDataset->AcquireMutex();
9053
0
    }
9054
9055
0
    return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9056
0
}
9057
9058
/************************************************************************/
9059
/*                            ReleaseMutex()                            */
9060
/************************************************************************/
9061
9062
void GDALDataset::ReleaseMutex()
9063
0
{
9064
0
    if (m_poPrivate)
9065
0
    {
9066
0
        if (m_poPrivate->poParentDataset)
9067
0
        {
9068
0
            m_poPrivate->poParentDataset->ReleaseMutex();
9069
0
            return;
9070
0
        }
9071
9072
0
        CPLReleaseMutex(m_poPrivate->hMutex);
9073
0
    }
9074
0
}
9075
9076
//! @endcond
9077
9078
/************************************************************************/
9079
/*               GDALDataset::Features::Iterator::Private               */
9080
/************************************************************************/
9081
9082
struct GDALDataset::Features::Iterator::Private
9083
{
9084
    GDALDataset::FeatureLayerPair m_oPair{};
9085
    GDALDataset *m_poDS = nullptr;
9086
    bool m_bEOF = true;
9087
};
9088
9089
GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9090
0
    : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9091
0
{
9092
0
    m_poPrivate->m_poDS = poDS;
9093
0
    if (bStart)
9094
0
    {
9095
0
        poDS->ResetReading();
9096
0
        m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9097
0
            &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9098
0
        m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9099
0
    }
9100
0
}
9101
9102
0
GDALDataset::Features::Iterator::~Iterator() = default;
9103
9104
const GDALDataset::FeatureLayerPair &
9105
GDALDataset::Features::Iterator::operator*() const
9106
0
{
9107
0
    return m_poPrivate->m_oPair;
9108
0
}
9109
9110
GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9111
0
{
9112
0
    m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9113
0
        &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9114
0
    m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9115
0
    return *this;
9116
0
}
9117
9118
bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9119
0
{
9120
0
    return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9121
0
}
9122
9123
/************************************************************************/
9124
/*                            GetFeatures()                             */
9125
/************************************************************************/
9126
9127
/** Function that return an iterable object over features in the dataset
9128
 * layer.
9129
 *
9130
 * This is a C++ iterator friendly version of GetNextFeature().
9131
 *
9132
 * Using this iterator for standard range-based loops is safe, but
9133
 * due to implementation limitations, you shouldn't try to access
9134
 * (dereference) more than one iterator step at a time, since the
9135
 * FeatureLayerPair reference which is returned is reused.
9136
 *
9137
 * Typical use is:
9138
 * \code{.cpp}
9139
 * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9140
 * {
9141
 *       std::cout << "Feature of layer " <<
9142
 *               oFeatureLayerPair.layer->GetName() << std::endl;
9143
 *       oFeatureLayerPair.feature->DumpReadable();
9144
 * }
9145
 * \endcode
9146
 *
9147
 * @see GetNextFeature()
9148
 *
9149
 */
9150
GDALDataset::Features GDALDataset::GetFeatures()
9151
0
{
9152
0
    return Features(this);
9153
0
}
9154
9155
/************************************************************************/
9156
/*                               begin()                                */
9157
/************************************************************************/
9158
9159
/**
9160
 \brief Return beginning of feature iterator.
9161
9162
*/
9163
9164
const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9165
0
{
9166
0
    return {m_poSelf, true};
9167
0
}
9168
9169
/************************************************************************/
9170
/*                                end()                                 */
9171
/************************************************************************/
9172
9173
/**
9174
 \brief Return end of feature iterator.
9175
9176
*/
9177
9178
const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9179
0
{
9180
0
    return {m_poSelf, false};
9181
0
}
9182
9183
/************************************************************************/
9184
/*                GDALDataset::Layers::Iterator::Private                */
9185
/************************************************************************/
9186
9187
struct GDALDataset::Layers::Iterator::Private
9188
{
9189
    OGRLayer *m_poLayer = nullptr;
9190
    int m_iCurLayer = 0;
9191
    int m_nLayerCount = 0;
9192
    GDALDataset *m_poDS = nullptr;
9193
};
9194
9195
0
GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9196
0
{
9197
0
}
9198
9199
// False positive of cppcheck 1.72
9200
// cppcheck-suppress uninitMemberVar
9201
GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9202
0
    : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9203
0
{
9204
0
}
9205
9206
GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9207
0
    : m_poPrivate(std::move(oOther.m_poPrivate))
9208
0
{
9209
0
}
9210
9211
GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9212
0
    : m_poPrivate(new Private())
9213
0
{
9214
0
    m_poPrivate->m_poDS = poDS;
9215
0
    m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9216
0
    if (bStart)
9217
0
    {
9218
0
        if (m_poPrivate->m_nLayerCount)
9219
0
            m_poPrivate->m_poLayer = poDS->GetLayer(0);
9220
0
    }
9221
0
    else
9222
0
    {
9223
0
        m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9224
0
    }
9225
0
}
9226
9227
0
GDALDataset::Layers::Iterator::~Iterator() = default;
9228
9229
// False positive of cppcheck 1.72
9230
// cppcheck-suppress operatorEqVarError
9231
GDALDataset::Layers::Iterator &
9232
GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9233
0
{
9234
0
    *m_poPrivate = *oOther.m_poPrivate;
9235
0
    return *this;
9236
0
}
9237
9238
GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9239
    GDALDataset::Layers::Iterator &&oOther) noexcept
9240
0
{
9241
0
    m_poPrivate = std::move(oOther.m_poPrivate);
9242
0
    return *this;
9243
0
}
9244
9245
OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9246
0
{
9247
0
    return m_poPrivate->m_poLayer;
9248
0
}
9249
9250
GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9251
0
{
9252
0
    m_poPrivate->m_iCurLayer++;
9253
0
    if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9254
0
    {
9255
0
        m_poPrivate->m_poLayer =
9256
0
            m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9257
0
    }
9258
0
    else
9259
0
    {
9260
0
        m_poPrivate->m_poLayer = nullptr;
9261
0
    }
9262
0
    return *this;
9263
0
}
9264
9265
GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9266
0
{
9267
0
    GDALDataset::Layers::Iterator temp = *this;
9268
0
    ++(*this);
9269
0
    return temp;
9270
0
}
9271
9272
bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9273
0
{
9274
0
    return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9275
0
}
9276
9277
/************************************************************************/
9278
/*                             GetLayers()                              */
9279
/************************************************************************/
9280
9281
/** Function that returns an iterable object over layers in the dataset.
9282
 *
9283
 * This is a C++ iterator friendly version of GetLayer().
9284
 *
9285
 * Typical use is:
9286
 * \code{.cpp}
9287
 * for( auto&& poLayer: poDS->GetLayers() )
9288
 * {
9289
 *       std::cout << "Layer  << poLayer->GetName() << std::endl;
9290
 * }
9291
 * \endcode
9292
 *
9293
 * @see GetLayer()
9294
 *
9295
 */
9296
GDALDataset::Layers GDALDataset::GetLayers()
9297
0
{
9298
0
    return Layers(this);
9299
0
}
9300
9301
/************************************************************************/
9302
/*                               begin()                                */
9303
/************************************************************************/
9304
9305
/**
9306
 \brief Return beginning of layer iterator.
9307
9308
*/
9309
9310
GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9311
0
{
9312
0
    return {m_poSelf, true};
9313
0
}
9314
9315
/************************************************************************/
9316
/*                                end()                                 */
9317
/************************************************************************/
9318
9319
/**
9320
 \brief Return end of layer iterator.
9321
9322
*/
9323
9324
GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9325
0
{
9326
0
    return {m_poSelf, false};
9327
0
}
9328
9329
/************************************************************************/
9330
/*                                size()                                */
9331
/************************************************************************/
9332
9333
/**
9334
 \brief Get the number of layers in this dataset.
9335
9336
 @return layer count.
9337
9338
*/
9339
9340
size_t GDALDataset::Layers::size() const
9341
0
{
9342
0
    return static_cast<size_t>(m_poSelf->GetLayerCount());
9343
0
}
9344
9345
/************************************************************************/
9346
/*                             operator[]()                             */
9347
/************************************************************************/
9348
/**
9349
 \brief Fetch a layer by index.
9350
9351
 The returned layer remains owned by the
9352
 GDALDataset and should not be deleted by the application.
9353
9354
 @param iLayer a layer number between 0 and size()-1.
9355
9356
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9357
9358
*/
9359
9360
OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9361
0
{
9362
0
    return m_poSelf->GetLayer(iLayer);
9363
0
}
9364
9365
/************************************************************************/
9366
/*                             operator[]()                             */
9367
/************************************************************************/
9368
/**
9369
 \brief Fetch a layer by index.
9370
9371
 The returned layer remains owned by the
9372
 GDALDataset and should not be deleted by the application.
9373
9374
 @param iLayer a layer number between 0 and size()-1.
9375
9376
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9377
9378
*/
9379
9380
OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9381
0
{
9382
0
    return m_poSelf->GetLayer(static_cast<int>(iLayer));
9383
0
}
9384
9385
/************************************************************************/
9386
/*                             operator[]()                             */
9387
/************************************************************************/
9388
/**
9389
 \brief Fetch a layer by name.
9390
9391
 The returned layer remains owned by the
9392
 GDALDataset and should not be deleted by the application.
9393
9394
 @param pszLayerName layer name
9395
9396
 @return the layer, or nullptr if pszLayerName does not match with a layer
9397
9398
*/
9399
9400
OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9401
0
{
9402
0
    return m_poSelf->GetLayerByName(pszLayerName);
9403
0
}
9404
9405
/************************************************************************/
9406
/*             GDALDataset::ConstLayers::Iterator::Private              */
9407
/************************************************************************/
9408
9409
struct GDALDataset::ConstLayers::Iterator::Private
9410
{
9411
    const OGRLayer *m_poLayer = nullptr;
9412
    int m_iCurLayer = 0;
9413
    int m_nLayerCount = 0;
9414
    const GDALDataset *m_poDS = nullptr;
9415
};
9416
9417
0
GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9418
0
{
9419
0
}
9420
9421
// False positive of cppcheck 1.72
9422
// cppcheck-suppress uninitMemberVar
9423
GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9424
0
    : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9425
0
{
9426
0
}
9427
9428
GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9429
0
    : m_poPrivate(std::move(oOther.m_poPrivate))
9430
0
{
9431
0
}
9432
9433
GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9434
                                             bool bStart)
9435
0
    : m_poPrivate(new Private())
9436
0
{
9437
0
    m_poPrivate->m_poDS = poDS;
9438
0
    m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9439
0
    if (bStart)
9440
0
    {
9441
0
        if (m_poPrivate->m_nLayerCount)
9442
0
            m_poPrivate->m_poLayer = poDS->GetLayer(0);
9443
0
    }
9444
0
    else
9445
0
    {
9446
0
        m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9447
0
    }
9448
0
}
9449
9450
0
GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9451
9452
// False positive of cppcheck 1.72
9453
// cppcheck-suppress operatorEqVarError
9454
GDALDataset::ConstLayers::Iterator &
9455
GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9456
0
{
9457
0
    *m_poPrivate = *oOther.m_poPrivate;
9458
0
    return *this;
9459
0
}
9460
9461
GDALDataset::ConstLayers::Iterator &
9462
GDALDataset::ConstLayers::Iterator::operator=(
9463
    GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9464
0
{
9465
0
    m_poPrivate = std::move(oOther.m_poPrivate);
9466
0
    return *this;
9467
0
}
9468
9469
const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9470
0
{
9471
0
    return m_poPrivate->m_poLayer;
9472
0
}
9473
9474
GDALDataset::ConstLayers::Iterator &
9475
GDALDataset::ConstLayers::Iterator::operator++()
9476
0
{
9477
0
    m_poPrivate->m_iCurLayer++;
9478
0
    if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9479
0
    {
9480
0
        m_poPrivate->m_poLayer =
9481
0
            m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9482
0
    }
9483
0
    else
9484
0
    {
9485
0
        m_poPrivate->m_poLayer = nullptr;
9486
0
    }
9487
0
    return *this;
9488
0
}
9489
9490
GDALDataset::ConstLayers::Iterator
9491
GDALDataset::ConstLayers::Iterator::operator++(int)
9492
0
{
9493
0
    GDALDataset::ConstLayers::Iterator temp = *this;
9494
0
    ++(*this);
9495
0
    return temp;
9496
0
}
9497
9498
bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9499
0
{
9500
0
    return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9501
0
}
9502
9503
/************************************************************************/
9504
/*                             GetLayers()                              */
9505
/************************************************************************/
9506
9507
/** Function that returns an iterable object over layers in the dataset.
9508
 *
9509
 * This is a C++ iterator friendly version of GetLayer().
9510
 *
9511
 * Typical use is:
9512
 * \code{.cpp}
9513
 * for( auto&& poLayer: poDS->GetLayers() )
9514
 * {
9515
 *       std::cout << "Layer  << poLayer->GetName() << std::endl;
9516
 * }
9517
 * \endcode
9518
 *
9519
 * @see GetLayer()
9520
 *
9521
 * @since GDAL 3.12
9522
 */
9523
GDALDataset::ConstLayers GDALDataset::GetLayers() const
9524
0
{
9525
0
    return ConstLayers(this);
9526
0
}
9527
9528
/************************************************************************/
9529
/*                               begin()                                */
9530
/************************************************************************/
9531
9532
/**
9533
 \brief Return beginning of layer iterator.
9534
9535
 @since GDAL 3.12
9536
*/
9537
9538
GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9539
0
{
9540
0
    return {m_poSelf, true};
9541
0
}
9542
9543
/************************************************************************/
9544
/*                                end()                                 */
9545
/************************************************************************/
9546
9547
/**
9548
 \brief Return end of layer iterator.
9549
9550
 @since GDAL 3.12
9551
*/
9552
9553
GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9554
0
{
9555
0
    return {m_poSelf, false};
9556
0
}
9557
9558
/************************************************************************/
9559
/*                                size()                                */
9560
/************************************************************************/
9561
9562
/**
9563
 \brief Get the number of layers in this dataset.
9564
9565
 @return layer count.
9566
9567
 @since GDAL 3.12
9568
*/
9569
9570
size_t GDALDataset::ConstLayers::size() const
9571
0
{
9572
0
    return static_cast<size_t>(m_poSelf->GetLayerCount());
9573
0
}
9574
9575
/************************************************************************/
9576
/*                             operator[]()                             */
9577
/************************************************************************/
9578
/**
9579
 \brief Fetch a layer by index.
9580
9581
 The returned layer remains owned by the
9582
 GDALDataset and should not be deleted by the application.
9583
9584
 @param iLayer a layer number between 0 and size()-1.
9585
9586
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9587
9588
 @since GDAL 3.12
9589
*/
9590
9591
const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9592
0
{
9593
0
    return m_poSelf->GetLayer(iLayer);
9594
0
}
9595
9596
/************************************************************************/
9597
/*                             operator[]()                             */
9598
/************************************************************************/
9599
/**
9600
 \brief Fetch a layer by index.
9601
9602
 The returned layer remains owned by the
9603
 GDALDataset and should not be deleted by the application.
9604
9605
 @param iLayer a layer number between 0 and size()-1.
9606
9607
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9608
9609
 @since GDAL 3.12
9610
*/
9611
9612
const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9613
0
{
9614
0
    return m_poSelf->GetLayer(static_cast<int>(iLayer));
9615
0
}
9616
9617
/************************************************************************/
9618
/*                             operator[]()                             */
9619
/************************************************************************/
9620
/**
9621
 \brief Fetch a layer by name.
9622
9623
 The returned layer remains owned by the
9624
 GDALDataset and should not be deleted by the application.
9625
9626
 @param pszLayerName layer name
9627
9628
 @return the layer, or nullptr if pszLayerName does not match with a layer
9629
9630
 @since GDAL 3.12
9631
*/
9632
9633
const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9634
0
{
9635
0
    return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9636
0
}
9637
9638
/************************************************************************/
9639
/*                GDALDataset::Bands::Iterator::Private                 */
9640
/************************************************************************/
9641
9642
struct GDALDataset::Bands::Iterator::Private
9643
{
9644
    GDALRasterBand *m_poBand = nullptr;
9645
    int m_iCurBand = 0;
9646
    int m_nBandCount = 0;
9647
    GDALDataset *m_poDS = nullptr;
9648
};
9649
9650
GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9651
0
    : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9652
0
{
9653
0
    m_poPrivate->m_poDS = poDS;
9654
0
    m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9655
0
    if (bStart)
9656
0
    {
9657
0
        if (m_poPrivate->m_nBandCount)
9658
0
            m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9659
0
    }
9660
0
    else
9661
0
    {
9662
0
        m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9663
0
    }
9664
0
}
9665
9666
0
GDALDataset::Bands::Iterator::~Iterator() = default;
9667
9668
GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9669
0
{
9670
0
    return m_poPrivate->m_poBand;
9671
0
}
9672
9673
GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9674
0
{
9675
0
    m_poPrivate->m_iCurBand++;
9676
0
    if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9677
0
    {
9678
0
        m_poPrivate->m_poBand =
9679
0
            m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9680
0
    }
9681
0
    else
9682
0
    {
9683
0
        m_poPrivate->m_poBand = nullptr;
9684
0
    }
9685
0
    return *this;
9686
0
}
9687
9688
bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9689
0
{
9690
0
    return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9691
0
}
9692
9693
/************************************************************************/
9694
/*                              GetBands()                              */
9695
/************************************************************************/
9696
9697
/** Function that returns an iterable object over GDALRasterBand in the dataset.
9698
 *
9699
 * This is a C++ iterator friendly version of GetRasterBand().
9700
 *
9701
 * Typical use is:
9702
 * \code{.cpp}
9703
 * for( auto&& poBand: poDS->GetBands() )
9704
 * {
9705
 *       std::cout << "Band  << poBand->GetDescription() << std::endl;
9706
 * }
9707
 * \endcode
9708
 *
9709
 * @see GetRasterBand()
9710
 *
9711
 */
9712
GDALDataset::Bands GDALDataset::GetBands()
9713
0
{
9714
0
    return Bands(this);
9715
0
}
9716
9717
/************************************************************************/
9718
/*                               begin()                                */
9719
/************************************************************************/
9720
9721
/**
9722
 \brief Return beginning of band iterator.
9723
9724
*/
9725
9726
const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9727
0
{
9728
0
    return {m_poSelf, true};
9729
0
}
9730
9731
/************************************************************************/
9732
/*                                end()                                 */
9733
/************************************************************************/
9734
9735
/**
9736
 \brief Return end of band iterator.
9737
9738
*/
9739
9740
const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9741
0
{
9742
0
    return {m_poSelf, false};
9743
0
}
9744
9745
/************************************************************************/
9746
/*                                size()                                */
9747
/************************************************************************/
9748
9749
/**
9750
 \brief Get the number of raster bands in this dataset.
9751
9752
 @return raster band count.
9753
9754
*/
9755
9756
size_t GDALDataset::Bands::size() const
9757
0
{
9758
0
    return static_cast<size_t>(m_poSelf->GetRasterCount());
9759
0
}
9760
9761
/************************************************************************/
9762
/*                             operator[]()                             */
9763
/************************************************************************/
9764
/**
9765
 \brief Fetch a raster band by index.
9766
9767
 The returned band remains owned by the
9768
 GDALDataset and should not be deleted by the application.
9769
9770
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9771
 consistent with the conventions of C/C++, i.e. starting at 0.
9772
9773
 @param iBand a band index between 0 and size()-1.
9774
9775
 @return the band, or nullptr if iBand is out of range or an error occurs.
9776
9777
*/
9778
9779
GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9780
0
{
9781
0
    return m_poSelf->GetRasterBand(1 + iBand);
9782
0
}
9783
9784
/************************************************************************/
9785
/*                             operator[]()                             */
9786
/************************************************************************/
9787
9788
/**
9789
 \brief Fetch a raster band by index.
9790
9791
 The returned band remains owned by the
9792
 GDALDataset and should not be deleted by the application.
9793
9794
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9795
 consistent with the conventions of C/C++, i.e. starting at 0.
9796
9797
 @param iBand a band index between 0 and size()-1.
9798
9799
 @return the band, or nullptr if iBand is out of range or an error occurs.
9800
9801
*/
9802
9803
GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9804
0
{
9805
0
    return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9806
0
}
9807
9808
/************************************************************************/
9809
/*              GDALDataset::ConstBands::Iterator::Private              */
9810
/************************************************************************/
9811
9812
struct GDALDataset::ConstBands::Iterator::Private
9813
{
9814
    const GDALRasterBand *m_poBand = nullptr;
9815
    int m_iCurBand = 0;
9816
    int m_nBandCount = 0;
9817
    const GDALDataset *m_poDS = nullptr;
9818
};
9819
9820
GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9821
                                            bool bStart)
9822
0
    : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9823
0
{
9824
0
    m_poPrivate->m_poDS = poDS;
9825
0
    m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9826
0
    if (bStart)
9827
0
    {
9828
0
        if (m_poPrivate->m_nBandCount)
9829
0
            m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9830
0
    }
9831
0
    else
9832
0
    {
9833
0
        m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9834
0
    }
9835
0
}
9836
9837
0
GDALDataset::ConstBands::Iterator::~Iterator() = default;
9838
9839
const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9840
0
{
9841
0
    return m_poPrivate->m_poBand;
9842
0
}
9843
9844
GDALDataset::ConstBands::Iterator &
9845
GDALDataset::ConstBands::Iterator::operator++()
9846
0
{
9847
0
    m_poPrivate->m_iCurBand++;
9848
0
    if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9849
0
    {
9850
0
        m_poPrivate->m_poBand =
9851
0
            m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9852
0
    }
9853
0
    else
9854
0
    {
9855
0
        m_poPrivate->m_poBand = nullptr;
9856
0
    }
9857
0
    return *this;
9858
0
}
9859
9860
bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9861
0
{
9862
0
    return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9863
0
}
9864
9865
/************************************************************************/
9866
/*                              GetBands()                              */
9867
/************************************************************************/
9868
9869
/** Function that returns an iterable object over GDALRasterBand in the dataset.
9870
 *
9871
 * This is a C++ iterator friendly version of GetRasterBand().
9872
 *
9873
 * Typical use is:
9874
 * \code{.cpp}
9875
 * for( const auto* poBand: poDS->GetConstBands() )
9876
 * {
9877
 *       std::cout << "Band  << poBand->GetDescription() << std::endl;
9878
 * }
9879
 * \endcode
9880
 *
9881
 * @see GetRasterBand()
9882
 *
9883
 * @since GDAL 3.12
9884
 */
9885
GDALDataset::ConstBands GDALDataset::GetBands() const
9886
0
{
9887
0
    return ConstBands(this);
9888
0
}
9889
9890
/************************************************************************/
9891
/*                               begin()                                */
9892
/************************************************************************/
9893
9894
/**
9895
 \brief Return beginning of band iterator.
9896
9897
 @since GDAL 3.12
9898
*/
9899
9900
const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9901
0
{
9902
0
    return {m_poSelf, true};
9903
0
}
9904
9905
/************************************************************************/
9906
/*                                end()                                 */
9907
/************************************************************************/
9908
9909
/**
9910
 \brief Return end of band iterator.
9911
9912
 @since GDAL 3.12
9913
*/
9914
9915
const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9916
0
{
9917
0
    return {m_poSelf, false};
9918
0
}
9919
9920
/************************************************************************/
9921
/*                                size()                                */
9922
/************************************************************************/
9923
9924
/**
9925
 \brief Get the number of raster bands in this dataset.
9926
9927
 @return raster band count.
9928
9929
 @since GDAL 3.12
9930
*/
9931
9932
size_t GDALDataset::ConstBands::size() const
9933
0
{
9934
0
    return static_cast<size_t>(m_poSelf->GetRasterCount());
9935
0
}
9936
9937
/************************************************************************/
9938
/*                             operator[]()                             */
9939
/************************************************************************/
9940
/**
9941
 \brief Fetch a raster band by index.
9942
9943
 The returned band remains owned by the
9944
 GDALDataset and should not be deleted by the application.
9945
9946
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9947
 consistent with the conventions of C/C++, i.e. starting at 0.
9948
9949
 @param iBand a band index between 0 and size()-1.
9950
9951
 @return the band, or nullptr if iBand is out of range or an error occurs.
9952
9953
 @since GDAL 3.12
9954
*/
9955
9956
const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9957
0
{
9958
0
    return m_poSelf->GetRasterBand(1 + iBand);
9959
0
}
9960
9961
/************************************************************************/
9962
/*                             operator[]()                             */
9963
/************************************************************************/
9964
9965
/**
9966
 \brief Fetch a raster band by index.
9967
9968
 The returned band remains owned by the
9969
 GDALDataset and should not be deleted by the application.
9970
9971
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9972
 consistent with the conventions of C/C++, i.e. starting at 0.
9973
9974
 @param iBand a band index between 0 and size()-1.
9975
9976
 @return the band, or nullptr if iBand is out of range or an error occurs.
9977
9978
 @since GDAL 3.12
9979
*/
9980
9981
const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9982
0
{
9983
0
    return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9984
0
}
9985
9986
/************************************************************************/
9987
/*                            GetRootGroup()                            */
9988
/************************************************************************/
9989
9990
/**
9991
 \brief Return the root GDALGroup of this dataset.
9992
9993
 Only valid for multidimensional datasets.
9994
9995
 This is the same as the C function GDALDatasetGetRootGroup().
9996
9997
 @since GDAL 3.1
9998
*/
9999
10000
std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
10001
0
{
10002
0
    return nullptr;
10003
0
}
10004
10005
/************************************************************************/
10006
/*                      GDALDatasetGetRootGroup()                       */
10007
/************************************************************************/
10008
10009
/** Return the root GDALGroup of this dataset.
10010
 *
10011
 * Only valid for multidimensional datasets.
10012
 *
10013
 * The returned value must be freed with GDALGroupRelease().
10014
 *
10015
 * This is the same as the C++ method GDALDataset::GetRootGroup().
10016
 *
10017
 * @since GDAL 3.1
10018
 */
10019
GDALGroupH GDALDatasetGetRootGroup(GDALDatasetH hDS)
10020
0
{
10021
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10022
0
    auto poGroup(GDALDataset::FromHandle(hDS)->GetRootGroup());
10023
0
    return poGroup ? new GDALGroupHS(poGroup) : nullptr;
10024
0
}
10025
10026
/************************************************************************/
10027
/*                        GDALDatasetAsMDArray()                        */
10028
/************************************************************************/
10029
10030
/** Return a view of this dataset as a 3D multidimensional GDALMDArray.
10031
 *
10032
 * If this dataset is not already marked as shared, it will be, so that the
10033
 * returned array holds a reference to it.
10034
 *
10035
 * If the dataset has a geotransform attached, the X and Y dimensions of the
10036
 * returned array will have an associated indexing variable.
10037
 *
10038
 * The currently supported list of options is:
10039
 * <ul>
10040
 * <li>DIM_ORDER=&lt;order&gt; where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
10041
 * "Band,Y,X" means that the first (slowest changing) dimension is Band
10042
 * and the last (fastest changing direction) is X
10043
 * "Y,X,Band" means that the first (slowest changing) dimension is Y
10044
 * and the last (fastest changing direction) is Band.
10045
 * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
10046
 * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
10047
 * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
10048
 * "Y,X,Band" is use.
10049
 * </li>
10050
 * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|&lt;BandMetadataItem&gt;:
10051
 * item from which to build the band indexing variable.
10052
 * <ul>
10053
 * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
10054
 * <li>"{None}" means that no band indexing variable must be created.</li>
10055
 * <li>"{Index}" means that the band index (starting at one) is used.</li>
10056
 * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
10057
 * <li>&lt;BandMetadataItem&gt; is the name of a band metadata item to use.</li>
10058
 * </ul>
10059
 * </li>
10060
 * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
10061
 * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
10062
 * Defaults to String.
10063
 * </li>
10064
 * <li>BAND_DIM_NAME=&lt;string&gt;: Name of the band dimension.
10065
 * Defaults to "Band".
10066
 * </li>
10067
 * <li>X_DIM_NAME=&lt;string&gt;: Name of the X dimension. Defaults to "X".
10068
 * </li>
10069
 * <li>Y_DIM_NAME=&lt;string&gt;: Name of the Y dimension. Defaults to "Y".
10070
 * </li>
10071
 * </ul>
10072
 *
10073
 * The returned pointer must be released with GDALMDArrayRelease().
10074
 *
10075
 * The "reverse" methods are GDALRasterBand::AsMDArray() and
10076
 * GDALDataset::AsMDArray()
10077
 *
10078
 * This is the same as the C++ method GDALDataset::AsMDArray().
10079
 *
10080
 * @param hDS Dataset handle.
10081
 * @param papszOptions Null-terminated list of strings, or nullptr.
10082
 * @return a new array, or NULL.
10083
 *
10084
 * @since GDAL 3.12
10085
 */
10086
GDALMDArrayH GDALDatasetAsMDArray(GDALDatasetH hDS, CSLConstList papszOptions)
10087
0
{
10088
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10089
0
    auto poArray(GDALDataset::FromHandle(hDS)->AsMDArray(papszOptions));
10090
0
    if (!poArray)
10091
0
        return nullptr;
10092
0
    return new GDALMDArrayHS(poArray);
10093
0
}
10094
10095
/************************************************************************/
10096
/*                         GetRawBinaryLayout()                         */
10097
/************************************************************************/
10098
10099
//! @cond Doxygen_Suppress
10100
/**
10101
 \brief Return the layout of a dataset that can be considered as a raw binary
10102
 format.
10103
10104
 @param sLayout Structure that will be set if the dataset is a raw binary one.
10105
 @return true if the dataset is a raw binary one.
10106
 @since GDAL 3.1
10107
*/
10108
10109
bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
10110
0
{
10111
0
    CPL_IGNORE_RET_VAL(sLayout);
10112
0
    return false;
10113
0
}
10114
10115
//! @endcond
10116
10117
/************************************************************************/
10118
/*                          ClearStatistics()                           */
10119
/************************************************************************/
10120
10121
/**
10122
 \brief Clear statistics
10123
10124
 Only implemented for now in PAM supported datasets
10125
10126
 This is the same as the C function GDALDatasetClearStatistics().
10127
10128
 @since GDAL 3.2
10129
*/
10130
10131
void GDALDataset::ClearStatistics()
10132
0
{
10133
0
    auto poRootGroup = GetRootGroup();
10134
0
    if (poRootGroup)
10135
0
        poRootGroup->ClearStatistics();
10136
0
}
10137
10138
/************************************************************************/
10139
/*                     GDALDatasetClearStatistics()                     */
10140
/************************************************************************/
10141
10142
/**
10143
 \brief Clear statistics
10144
10145
 This is the same as the C++ method GDALDataset::ClearStatistics().
10146
10147
 @since GDAL 3.2
10148
*/
10149
10150
void GDALDatasetClearStatistics(GDALDatasetH hDS)
10151
0
{
10152
0
    VALIDATE_POINTER0(hDS, __func__);
10153
0
    GDALDataset::FromHandle(hDS)->ClearStatistics();
10154
0
}
10155
10156
/************************************************************************/
10157
/*                        GetFieldDomainNames()                         */
10158
/************************************************************************/
10159
10160
/** Returns a list of the names of all field domains stored in the dataset.
10161
 *
10162
 * @note The default implementation assumes that drivers fully populate
10163
 * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10164
 * then a specialized implementation of GetFieldDomainNames() must be
10165
 * implemented.
10166
 *
10167
 * @param papszOptions Driver specific options determining how attributes
10168
 * should be retrieved. Pass nullptr for default behavior.
10169
 *
10170
 * @return list of field domain names
10171
 * @since GDAL 3.5
10172
 */
10173
std::vector<std::string>
10174
GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10175
0
{
10176
10177
0
    std::vector<std::string> names;
10178
0
    names.reserve(m_oMapFieldDomains.size());
10179
0
    for (const auto &it : m_oMapFieldDomains)
10180
0
    {
10181
0
        names.emplace_back(it.first);
10182
0
    }
10183
0
    return names;
10184
0
}
10185
10186
/************************************************************************/
10187
/*                   GDALDatasetGetFieldDomainNames()                   */
10188
/************************************************************************/
10189
10190
/** Returns a list of the names of all field domains stored in the dataset.
10191
 *
10192
 * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10193
 *
10194
 * @param hDS Dataset handle.
10195
 * @param papszOptions Driver specific options determining how attributes
10196
 * should be retrieved. Pass nullptr for default behavior.
10197
 *
10198
 * @return list of field domain names, to be freed with CSLDestroy()
10199
 * @since GDAL 3.5
10200
 */
10201
char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10202
                                      CSLConstList papszOptions)
10203
0
{
10204
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10205
0
    auto names =
10206
0
        GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10207
0
    CPLStringList res;
10208
0
    for (const auto &name : names)
10209
0
    {
10210
0
        res.AddString(name.c_str());
10211
0
    }
10212
0
    return res.StealList();
10213
0
}
10214
10215
/************************************************************************/
10216
/*                           GetFieldDomain()                           */
10217
/************************************************************************/
10218
10219
/** Get a field domain from its name.
10220
 *
10221
 * @return the field domain, or nullptr if not found.
10222
 * @since GDAL 3.3
10223
 */
10224
const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10225
0
{
10226
0
    const auto iter = m_oMapFieldDomains.find(name);
10227
0
    if (iter == m_oMapFieldDomains.end())
10228
0
        return nullptr;
10229
0
    return iter->second.get();
10230
0
}
10231
10232
/************************************************************************/
10233
/*                     GDALDatasetGetFieldDomain()                      */
10234
/************************************************************************/
10235
10236
/** Get a field domain from its name.
10237
 *
10238
 * This is the same as the C++ method GDALDataset::GetFieldDomain().
10239
 *
10240
 * @param hDS Dataset handle.
10241
 * @param pszName Name of field domain.
10242
 * @return the field domain (ownership remains to the dataset), or nullptr if
10243
 * not found.
10244
 * @since GDAL 3.3
10245
 */
10246
OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10247
0
{
10248
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10249
0
    VALIDATE_POINTER1(pszName, __func__, nullptr);
10250
0
    return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10251
0
        GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10252
0
}
10253
10254
/************************************************************************/
10255
/*                           AddFieldDomain()                           */
10256
/************************************************************************/
10257
10258
/** Add a field domain to the dataset.
10259
 *
10260
 * Only a few drivers will support this operation, and some of them might only
10261
 * support it only for some types of field domains.
10262
 * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10263
 * support this operation. A dataset having at least some support for this
10264
 * operation should report the ODsCAddFieldDomain dataset capability.
10265
 *
10266
 * Anticipated failures will not be emitted through the CPLError()
10267
 * infrastructure, but will be reported in the failureReason output parameter.
10268
 *
10269
 * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10270
 * default implementation of GetFieldDomainNames() to work correctly, or
10271
 * alternatively a specialized implementation of GetFieldDomainNames() should be
10272
 * implemented.
10273
 *
10274
 * @param domain The domain definition.
10275
 * @param failureReason      Output parameter. Will contain an error message if
10276
 *                           an error occurs.
10277
 * @return true in case of success.
10278
 * @since GDAL 3.3
10279
 */
10280
bool GDALDataset::AddFieldDomain(
10281
    CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10282
    std::string &failureReason)
10283
0
{
10284
0
    failureReason = "AddFieldDomain not supported by this driver";
10285
0
    return false;
10286
0
}
10287
10288
/************************************************************************/
10289
/*                     GDALDatasetAddFieldDomain()                      */
10290
/************************************************************************/
10291
10292
/** Add a field domain to the dataset.
10293
 *
10294
 * Only a few drivers will support this operation, and some of them might only
10295
 * support it only for some types of field domains.
10296
 * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10297
 * support this operation. A dataset having at least some support for this
10298
 * operation should report the ODsCAddFieldDomain dataset capability.
10299
 *
10300
 * Anticipated failures will not be emitted through the CPLError()
10301
 * infrastructure, but will be reported in the ppszFailureReason output
10302
 * parameter.
10303
 *
10304
 * @param hDS                Dataset handle.
10305
 * @param hFieldDomain       The domain definition. Contrary to the C++ version,
10306
 *                           the passed object is copied.
10307
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10308
 *                           an error occurs (*ppszFailureReason to be freed
10309
 *                           with CPLFree). May be NULL.
10310
 * @return true in case of success.
10311
 * @since GDAL 3.3
10312
 */
10313
bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10314
                               char **ppszFailureReason)
10315
0
{
10316
0
    VALIDATE_POINTER1(hDS, __func__, false);
10317
0
    VALIDATE_POINTER1(hFieldDomain, __func__, false);
10318
0
    auto poDomain = std::unique_ptr<OGRFieldDomain>(
10319
0
        OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10320
0
    if (poDomain == nullptr)
10321
0
        return false;
10322
0
    std::string failureReason;
10323
0
    const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10324
0
        std::move(poDomain), failureReason);
10325
0
    if (ppszFailureReason)
10326
0
    {
10327
0
        *ppszFailureReason =
10328
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10329
0
    }
10330
0
    return bRet;
10331
0
}
10332
10333
/************************************************************************/
10334
/*                         DeleteFieldDomain()                          */
10335
/************************************************************************/
10336
10337
/** Removes a field domain from the dataset.
10338
 *
10339
 * Only a few drivers will support this operation.
10340
 *
10341
 * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10342
 * support this operation. A dataset having at least some support for this
10343
 * operation should report the ODsCDeleteFieldDomain dataset capability.
10344
 *
10345
 * Anticipated failures will not be emitted through the CPLError()
10346
 * infrastructure, but will be reported in the failureReason output parameter.
10347
 *
10348
 * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10349
 * default implementation of GetFieldDomainNames() to work correctly, or
10350
 * alternatively a specialized implementation of GetFieldDomainNames() should be
10351
 * implemented.
10352
 *
10353
 * @param name The domain name.
10354
 * @param failureReason      Output parameter. Will contain an error message if
10355
 *                           an error occurs.
10356
 * @return true in case of success.
10357
 * @since GDAL 3.5
10358
 */
10359
bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10360
                                    std::string &failureReason)
10361
0
{
10362
0
    failureReason = "DeleteFieldDomain not supported by this driver";
10363
0
    return false;
10364
0
}
10365
10366
/************************************************************************/
10367
/*                    GDALDatasetDeleteFieldDomain()                    */
10368
/************************************************************************/
10369
10370
/** Removes a field domain from the dataset.
10371
 *
10372
 * Only a few drivers will support this operation.
10373
 *
10374
 * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10375
 * support this operation. A dataset having at least some support for this
10376
 * operation should report the ODsCDeleteFieldDomain dataset capability.
10377
 *
10378
 * Anticipated failures will not be emitted through the CPLError()
10379
 * infrastructure, but will be reported in the ppszFailureReason output
10380
 * parameter.
10381
 *
10382
 * @param hDS                Dataset handle.
10383
 * @param pszName            The domain name.
10384
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10385
 *                           an error occurs (*ppszFailureReason to be freed
10386
 *                           with CPLFree). May be NULL.
10387
 * @return true in case of success.
10388
 * @since GDAL 3.3
10389
 */
10390
bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10391
                                  char **ppszFailureReason)
10392
0
{
10393
0
    VALIDATE_POINTER1(hDS, __func__, false);
10394
0
    VALIDATE_POINTER1(pszName, __func__, false);
10395
0
    std::string failureReason;
10396
0
    const bool bRet =
10397
0
        GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10398
0
    if (ppszFailureReason)
10399
0
    {
10400
0
        *ppszFailureReason =
10401
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10402
0
    }
10403
0
    return bRet;
10404
0
}
10405
10406
/************************************************************************/
10407
/*                         UpdateFieldDomain()                          */
10408
/************************************************************************/
10409
10410
/** Updates an existing field domain by replacing its definition.
10411
 *
10412
 * The existing field domain with matching name will be replaced.
10413
 *
10414
 * Only a few drivers will support this operation, and some of them might only
10415
 * support it only for some types of field domains.
10416
 * At the time of writing (GDAL 3.5), only the Memory driver
10417
 * supports this operation. A dataset having at least some support for this
10418
 * operation should report the ODsCUpdateFieldDomain dataset capability.
10419
 *
10420
 * Anticipated failures will not be emitted through the CPLError()
10421
 * infrastructure, but will be reported in the failureReason output parameter.
10422
 *
10423
 * @param domain The domain definition.
10424
 * @param failureReason      Output parameter. Will contain an error message if
10425
 *                           an error occurs.
10426
 * @return true in case of success.
10427
 * @since GDAL 3.5
10428
 */
10429
bool GDALDataset::UpdateFieldDomain(
10430
    CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10431
    std::string &failureReason)
10432
0
{
10433
0
    failureReason = "UpdateFieldDomain not supported by this driver";
10434
0
    return false;
10435
0
}
10436
10437
/************************************************************************/
10438
/*                    GDALDatasetUpdateFieldDomain()                    */
10439
/************************************************************************/
10440
10441
/** Updates an existing field domain by replacing its definition.
10442
 *
10443
 * The existing field domain with matching name will be replaced.
10444
 *
10445
 * Only a few drivers will support this operation, and some of them might only
10446
 * support it only for some types of field domains.
10447
 * At the time of writing (GDAL 3.5), only the Memory driver
10448
 * supports this operation. A dataset having at least some support for this
10449
 * operation should report the ODsCUpdateFieldDomain dataset capability.
10450
 *
10451
 * Anticipated failures will not be emitted through the CPLError()
10452
 * infrastructure, but will be reported in the failureReason output parameter.
10453
 *
10454
 * @param hDS                Dataset handle.
10455
 * @param hFieldDomain       The domain definition. Contrary to the C++ version,
10456
 *                           the passed object is copied.
10457
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10458
 *                           an error occurs (*ppszFailureReason to be freed
10459
 *                           with CPLFree). May be NULL.
10460
 * @return true in case of success.
10461
 * @since GDAL 3.5
10462
 */
10463
bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10464
                                  OGRFieldDomainH hFieldDomain,
10465
                                  char **ppszFailureReason)
10466
0
{
10467
0
    VALIDATE_POINTER1(hDS, __func__, false);
10468
0
    VALIDATE_POINTER1(hFieldDomain, __func__, false);
10469
0
    auto poDomain = std::unique_ptr<OGRFieldDomain>(
10470
0
        OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10471
0
    if (poDomain == nullptr)
10472
0
        return false;
10473
0
    std::string failureReason;
10474
0
    const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10475
0
        std::move(poDomain), failureReason);
10476
0
    if (ppszFailureReason)
10477
0
    {
10478
0
        *ppszFailureReason =
10479
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10480
0
    }
10481
0
    return bRet;
10482
0
}
10483
10484
/************************************************************************/
10485
/*                        GetRelationshipNames()                        */
10486
/************************************************************************/
10487
10488
/** Returns a list of the names of all relationships stored in the dataset.
10489
 *
10490
 * @param papszOptions Driver specific options determining how relationships
10491
 * should be retrieved. Pass nullptr for default behavior.
10492
 *
10493
 * @return list of relationship names
10494
 * @since GDAL 3.6
10495
 */
10496
std::vector<std::string>
10497
GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10498
0
{
10499
0
    return {};
10500
0
}
10501
10502
/************************************************************************/
10503
/*                  GDALDatasetGetRelationshipNames()                   */
10504
/************************************************************************/
10505
10506
/** Returns a list of the names of all relationships stored in the dataset.
10507
 *
10508
 * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10509
 *
10510
 * @param hDS Dataset handle.
10511
 * @param papszOptions Driver specific options determining how relationships
10512
 * should be retrieved. Pass nullptr for default behavior.
10513
 *
10514
 * @return list of relationship names, to be freed with CSLDestroy()
10515
 * @since GDAL 3.6
10516
 */
10517
char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10518
                                       CSLConstList papszOptions)
10519
0
{
10520
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10521
0
    auto names =
10522
0
        GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10523
0
    CPLStringList res;
10524
0
    for (const auto &name : names)
10525
0
    {
10526
0
        res.AddString(name.c_str());
10527
0
    }
10528
0
    return res.StealList();
10529
0
}
10530
10531
/************************************************************************/
10532
/*                          GetRelationship()                           */
10533
/************************************************************************/
10534
10535
/** Get a relationship from its name.
10536
 *
10537
 * @return the relationship, or nullptr if not found.
10538
 * @since GDAL 3.6
10539
 */
10540
const GDALRelationship *
10541
GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10542
0
{
10543
0
    return nullptr;
10544
0
}
10545
10546
/************************************************************************/
10547
/*                     GDALDatasetGetRelationship()                     */
10548
/************************************************************************/
10549
10550
/** Get a relationship from its name.
10551
 *
10552
 * This is the same as the C++ method GDALDataset::GetRelationship().
10553
 *
10554
 * @param hDS Dataset handle.
10555
 * @param pszName Name of relationship.
10556
 * @return the relationship (ownership remains to the dataset), or nullptr if
10557
 * not found.
10558
 * @since GDAL 3.6
10559
 */
10560
GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10561
                                             const char *pszName)
10562
0
{
10563
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10564
0
    VALIDATE_POINTER1(pszName, __func__, nullptr);
10565
0
    return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10566
0
        GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10567
0
}
10568
10569
/************************************************************************/
10570
/*                          AddRelationship()                           */
10571
/************************************************************************/
10572
10573
/** Add a relationship to the dataset.
10574
 *
10575
 * Only a few drivers will support this operation, and some of them might only
10576
 * support it only for some types of relationships.
10577
 *
10578
 * A dataset having at least some support for this
10579
 * operation should report the GDsCAddRelationship dataset capability.
10580
 *
10581
 * Anticipated failures will not be emitted through the CPLError()
10582
 * infrastructure, but will be reported in the failureReason output parameter.
10583
 *
10584
 * When adding a many-to-many relationship
10585
 * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10586
 * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10587
 * the driver to create an appropriately named and structured mapping table.
10588
 * Some dataset formats require particular naming conventions and field
10589
 * structures for the mapping table, and delegating the construction of the
10590
 * mapping table to the driver will avoid these pitfalls.
10591
 *
10592
 * @param relationship The relationship definition.
10593
 * @param failureReason      Output parameter. Will contain an error message if
10594
 *                           an error occurs.
10595
 * @return true in case of success.
10596
 * @since GDAL 3.6
10597
 */
10598
bool GDALDataset::AddRelationship(
10599
    CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10600
    std::string &failureReason)
10601
0
{
10602
0
    failureReason = "AddRelationship not supported by this driver";
10603
0
    return false;
10604
0
}
10605
10606
/************************************************************************/
10607
/*                     GDALDatasetAddRelationship()                     */
10608
/************************************************************************/
10609
10610
/** Add a relationship to the dataset.
10611
 *
10612
 * Only a few drivers will support this operation, and some of them might only
10613
 * support it only for some types of relationships.
10614
 *
10615
 * A dataset having at least some support for this
10616
 * operation should report the GDsCAddRelationship dataset capability.
10617
 *
10618
 * Anticipated failures will not be emitted through the CPLError()
10619
 * infrastructure, but will be reported in the failureReason output parameter.
10620
 *
10621
 * When adding a many-to-many relationship
10622
 * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10623
 * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10624
 * driver to create an appropriately named and structured mapping table. Some
10625
 * dataset formats require particular naming conventions and field structures
10626
 * for the mapping table, and delegating the construction of the mapping table
10627
 * to the driver will avoid these pitfalls.
10628
 *
10629
 * @param hDS                Dataset handle.
10630
 * @param hRelationship      The relationship definition. Contrary to the C++
10631
 * version, the passed object is copied.
10632
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10633
 *                           an error occurs (*ppszFailureReason to be freed
10634
 *                           with CPLFree). May be NULL.
10635
 * @return true in case of success.
10636
 * @since GDAL 3.6
10637
 */
10638
bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10639
                                GDALRelationshipH hRelationship,
10640
                                char **ppszFailureReason)
10641
0
{
10642
0
    VALIDATE_POINTER1(hDS, __func__, false);
10643
0
    VALIDATE_POINTER1(hRelationship, __func__, false);
10644
0
    std::unique_ptr<GDALRelationship> poRelationship(
10645
0
        new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10646
0
    std::string failureReason;
10647
0
    const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10648
0
        std::move(poRelationship), failureReason);
10649
0
    if (ppszFailureReason)
10650
0
    {
10651
0
        *ppszFailureReason =
10652
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10653
0
    }
10654
0
    return bRet;
10655
0
}
10656
10657
/************************************************************************/
10658
/*                         DeleteRelationship()                         */
10659
/************************************************************************/
10660
10661
/** Removes a relationship from the dataset.
10662
 *
10663
 * Only a few drivers will support this operation.
10664
 *
10665
 * A dataset having at least some support for this
10666
 * operation should report the GDsCDeleteRelationship dataset capability.
10667
 *
10668
 * Anticipated failures will not be emitted through the CPLError()
10669
 * infrastructure, but will be reported in the failureReason output parameter.
10670
 *
10671
 * @param name The relationship name.
10672
 * @param failureReason      Output parameter. Will contain an error message if
10673
 *                           an error occurs.
10674
 * @return true in case of success.
10675
 * @since GDAL 3.6
10676
 */
10677
bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10678
                                     std::string &failureReason)
10679
0
{
10680
0
    failureReason = "DeleteRelationship not supported by this driver";
10681
0
    return false;
10682
0
}
10683
10684
/************************************************************************/
10685
/*                   GDALDatasetDeleteRelationship()                    */
10686
/************************************************************************/
10687
10688
/** Removes a relationship from the dataset.
10689
 *
10690
 * Only a few drivers will support this operation.
10691
 *
10692
 * A dataset having at least some support for this
10693
 * operation should report the GDsCDeleteRelationship dataset capability.
10694
 *
10695
 * Anticipated failures will not be emitted through the CPLError()
10696
 * infrastructure, but will be reported in the ppszFailureReason output
10697
 * parameter.
10698
 *
10699
 * @param hDS                Dataset handle.
10700
 * @param pszName            The relationship name.
10701
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10702
 *                           an error occurs (*ppszFailureReason to be freed
10703
 *                           with CPLFree). May be NULL.
10704
 * @return true in case of success.
10705
 * @since GDAL 3.6
10706
 */
10707
bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10708
                                   char **ppszFailureReason)
10709
0
{
10710
0
    VALIDATE_POINTER1(hDS, __func__, false);
10711
0
    VALIDATE_POINTER1(pszName, __func__, false);
10712
0
    std::string failureReason;
10713
0
    const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10714
0
        pszName, failureReason);
10715
0
    if (ppszFailureReason)
10716
0
    {
10717
0
        *ppszFailureReason =
10718
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10719
0
    }
10720
0
    return bRet;
10721
0
}
10722
10723
/************************************************************************/
10724
/*                         UpdateRelationship()                         */
10725
/************************************************************************/
10726
10727
/** Updates an existing relationship by replacing its definition.
10728
 *
10729
 * The existing relationship with matching name will be replaced.
10730
 *
10731
 * Only a few drivers will support this operation, and some of them might only
10732
 * support it only for some types of relationships.
10733
 * A dataset having at least some support for this
10734
 * operation should report the GDsCUpdateRelationship dataset capability.
10735
 *
10736
 * Anticipated failures will not be emitted through the CPLError()
10737
 * infrastructure, but will be reported in the failureReason output parameter.
10738
 *
10739
 * @param relationship   The relationship definition.
10740
 * @param failureReason  Output parameter. Will contain an error message if
10741
 *                       an error occurs.
10742
 * @return true in case of success.
10743
 * @since GDAL 3.6
10744
 */
10745
bool GDALDataset::UpdateRelationship(
10746
    CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10747
    std::string &failureReason)
10748
0
{
10749
0
    failureReason = "UpdateRelationship not supported by this driver";
10750
0
    return false;
10751
0
}
10752
10753
/************************************************************************/
10754
/*                   GDALDatasetUpdateRelationship()                    */
10755
/************************************************************************/
10756
10757
/** Updates an existing relationship by replacing its definition.
10758
 *
10759
 * The existing relationship with matching name will be replaced.
10760
 *
10761
 * Only a few drivers will support this operation, and some of them might only
10762
 * support it only for some types of relationships.
10763
 * A dataset having at least some support for this
10764
 * operation should report the GDsCUpdateRelationship dataset capability.
10765
 *
10766
 * Anticipated failures will not be emitted through the CPLError()
10767
 * infrastructure, but will be reported in the failureReason output parameter.
10768
 *
10769
 * @param hDS                Dataset handle.
10770
 * @param hRelationship      The relationship definition. Contrary to the C++
10771
 * version, the passed object is copied.
10772
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10773
 *                           an error occurs (*ppszFailureReason to be freed
10774
 *                           with CPLFree). May be NULL.
10775
 * @return true in case of success.
10776
 * @since GDAL 3.5
10777
 */
10778
bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10779
                                   GDALRelationshipH hRelationship,
10780
                                   char **ppszFailureReason)
10781
0
{
10782
0
    VALIDATE_POINTER1(hDS, __func__, false);
10783
0
    VALIDATE_POINTER1(hRelationship, __func__, false);
10784
0
    std::unique_ptr<GDALRelationship> poRelationship(
10785
0
        new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10786
0
    std::string failureReason;
10787
0
    const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10788
0
        std::move(poRelationship), failureReason);
10789
0
    if (ppszFailureReason)
10790
0
    {
10791
0
        *ppszFailureReason =
10792
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10793
0
    }
10794
0
    return bRet;
10795
0
}
10796
10797
/************************************************************************/
10798
/*                   GDALDatasetSetQueryLoggerFunc()                    */
10799
/************************************************************************/
10800
10801
/**
10802
 * Sets the SQL query logger callback.
10803
 *
10804
 * When supported by the driver, the callback will be called with
10805
 * the executed SQL text, the error message, the execution time in milliseconds,
10806
 * the number of records fetched/affected and the client status data.
10807
 *
10808
 * A value of -1 in the execution time or in the number of records indicates
10809
 * that the values are unknown.
10810
 *
10811
 * @param hDS                   Dataset handle.
10812
 * @param pfnQueryLoggerFunc    Callback function
10813
 * @param poQueryLoggerArg      Opaque client status data
10814
 * @return                      true in case of success.
10815
 * @since                       GDAL 3.7
10816
 */
10817
bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10818
                                   GDALQueryLoggerFunc pfnQueryLoggerFunc,
10819
                                   void *poQueryLoggerArg)
10820
0
{
10821
0
    VALIDATE_POINTER1(hDS, __func__, false);
10822
0
    return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10823
0
                                                            poQueryLoggerArg);
10824
0
}
10825
10826
//! @cond Doxygen_Suppress
10827
10828
/************************************************************************/
10829
/*                         SetEnableOverviews()                         */
10830
/************************************************************************/
10831
10832
void GDALDataset::SetEnableOverviews(bool bEnable)
10833
0
{
10834
0
    if (m_poPrivate)
10835
0
    {
10836
0
        m_poPrivate->m_bOverviewsEnabled = bEnable;
10837
0
    }
10838
0
}
10839
10840
/************************************************************************/
10841
/*                        AreOverviewsEnabled()                         */
10842
/************************************************************************/
10843
10844
bool GDALDataset::AreOverviewsEnabled() const
10845
0
{
10846
0
    return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10847
0
}
10848
10849
/************************************************************************/
10850
/*                             IsAllBands()                             */
10851
/************************************************************************/
10852
10853
bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10854
0
{
10855
0
    if (nBands != nBandCount)
10856
0
        return false;
10857
0
    if (panBandList)
10858
0
    {
10859
0
        for (int i = 0; i < nBandCount; ++i)
10860
0
        {
10861
0
            if (panBandList[i] != i + 1)
10862
0
                return false;
10863
0
        }
10864
0
    }
10865
0
    return true;
10866
0
}
10867
10868
//! @endcond
10869
10870
/************************************************************************/
10871
/*                       GetCompressionFormats()                        */
10872
/************************************************************************/
10873
10874
/** Return the compression formats that can be natively obtained for the
10875
 * window of interest and requested bands.
10876
 *
10877
 * For example, a tiled dataset may be able to return data in a compressed
10878
 * format if the window of interest matches exactly a tile. For some formats,
10879
 * drivers may also be able to merge several tiles together (not currently
10880
 * implemented though).
10881
 *
10882
 * Each format string is a pseudo MIME type, whose first part can be passed
10883
 * as the pszFormat argument of ReadCompressedData(), with additional
10884
 * parameters specified as key=value with a semi-colon separator.
10885
 *
10886
 * The amount and types of optional parameters passed after the MIME type is
10887
 * format dependent, and driver dependent (some drivers might not be able to
10888
 * return those extra information without doing a rather costly processing).
10889
 *
10890
 * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10891
 * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10892
 * consequently "JPEG" can be passed as the pszFormat argument of
10893
 * ReadCompressedData(). For JPEG, implementations can use the
10894
 * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10895
 * above from a JPEG codestream.
10896
 *
10897
 * Several values might be returned. For example,
10898
 * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10899
 * if the JPEGXL codestream includes a JPEG reconstruction box.
10900
 *
10901
 * In the general case this method will return an empty list.
10902
 *
10903
 * This is the same as C function GDALDatasetGetCompressionFormats().
10904
 *
10905
 * @param nXOff The pixel offset to the top left corner of the region
10906
 * of the band to be accessed.  This would be zero to start from the left side.
10907
 *
10908
 * @param nYOff The line offset to the top left corner of the region
10909
 * of the band to be accessed.  This would be zero to start from the top.
10910
 *
10911
 * @param nXSize The width of the region of the band to be accessed in pixels.
10912
 *
10913
 * @param nYSize The height of the region of the band to be accessed in lines.
10914
 *
10915
 * @param nBandCount the number of bands being requested.
10916
 *
10917
 * @param panBandList the list of nBandCount band numbers.
10918
 * Note band numbers are 1 based. This may be NULL to select the first
10919
 * nBandCount bands.
10920
 *
10921
 * @return a list of compatible formats (which may be empty)
10922
 *
10923
 * For example, to check if native compression format(s) are available on the
10924
 * whole image:
10925
 * \code{.cpp}
10926
 *   const CPLStringList aosFormats =
10927
 *      poDataset->GetCompressionFormats(0, 0,
10928
 *                                       poDataset->GetRasterXSize(),
10929
 *                                       poDataset->GetRasterYSize(),
10930
 *                                       poDataset->GetRasterCount(),
10931
 *                                       nullptr);
10932
 *   for( const char* pszFormat: aosFormats )
10933
 *   {
10934
 *      // Remove optional parameters and just print out the MIME type.
10935
 *      const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10936
 *      printf("Found format %s\n, aosTokens[0]);
10937
 *   }
10938
 * \endcode
10939
 *
10940
 * @since GDAL 3.7
10941
 */
10942
CPLStringList
10943
GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10944
                                   CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10945
                                   CPL_UNUSED int nBandCount,
10946
                                   CPL_UNUSED const int *panBandList)
10947
0
{
10948
0
    return CPLStringList();
10949
0
}
10950
10951
/************************************************************************/
10952
/*                  GDALDatasetGetCompressionFormats()                  */
10953
/************************************************************************/
10954
10955
/** Return the compression formats that can be natively obtained for the
10956
 * window of interest and requested bands.
10957
 *
10958
 * For example, a tiled dataset may be able to return data in a compressed
10959
 * format if the window of interest matches exactly a tile. For some formats,
10960
 * drivers may also be able to merge several tiles together (not currently
10961
 * implemented though).
10962
 *
10963
 * Each format string is a pseudo MIME type, whose first part can be passed
10964
 * as the pszFormat argument of ReadCompressedData(), with additional
10965
 * parameters specified as key=value with a semi-colon separator.
10966
 *
10967
 * The amount and types of optional parameters passed after the MIME type is
10968
 * format dependent, and driver dependent (some drivers might not be able to
10969
 * return those extra information without doing a rather costly processing).
10970
 *
10971
 * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10972
 * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10973
 * consequently "JPEG" can be passed as the pszFormat argument of
10974
 * ReadCompressedData(). For JPEG, implementations can use the
10975
 * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10976
 * above from a JPEG codestream.
10977
 *
10978
 * Several values might be returned. For example,
10979
 * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10980
 * if the JPEGXL codestream includes a JPEG reconstruction box.
10981
 *
10982
 * In the general case this method will return an empty list.
10983
 *
10984
 * This is the same as C++ method GDALDataset::GetCompressionFormats().
10985
 *
10986
 * @param hDS Dataset handle.
10987
 *
10988
 * @param nXOff The pixel offset to the top left corner of the region
10989
 * of the band to be accessed.  This would be zero to start from the left side.
10990
 *
10991
 * @param nYOff The line offset to the top left corner of the region
10992
 * of the band to be accessed.  This would be zero to start from the top.
10993
 *
10994
 * @param nXSize The width of the region of the band to be accessed in pixels.
10995
 *
10996
 * @param nYSize The height of the region of the band to be accessed in lines.
10997
 *
10998
 * @param nBandCount the number of bands being requested.
10999
 *
11000
 * @param panBandList the list of nBandCount band numbers.
11001
 * Note band numbers are 1 based. This may be NULL to select the first
11002
 * nBandCount bands.
11003
 *
11004
 * @return a list of compatible formats (which may be empty) that should be
11005
 * freed with CSLDestroy(), or nullptr.
11006
 *
11007
 * @since GDAL 3.7
11008
 */
11009
char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
11010
                                        int nXSize, int nYSize, int nBandCount,
11011
                                        const int *panBandList)
11012
0
{
11013
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
11014
0
    return GDALDataset::FromHandle(hDS)
11015
0
        ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
11016
0
                                panBandList)
11017
0
        .StealList();
11018
0
}
11019
11020
/************************************************************************/
11021
/*                         ReadCompressedData()                         */
11022
/************************************************************************/
11023
11024
/** Return the compressed content that can be natively obtained for the
11025
 * window of interest and requested bands.
11026
 *
11027
 * For example, a tiled dataset may be able to return data in compressed format
11028
 * if the window of interest matches exactly a tile. For some formats, drivers
11029
 * may also be example to merge several tiles together (not currently
11030
 * implemented though).
11031
 *
11032
 * The implementation should make sure that the content returned forms a valid
11033
 * standalone file. For example, for the GeoTIFF implementation of this method,
11034
 * when extracting a JPEG tile, the method will automatically add the content
11035
 * of the JPEG Huffman and/or quantization tables that might be stored in the
11036
 * TIFF JpegTables tag, and not in tile data itself.
11037
 *
11038
 * In the general case this method will return CE_Failure.
11039
 *
11040
 * This is the same as C function GDALDatasetReadCompressedData().
11041
 *
11042
 * @param pszFormat Requested compression format (e.g. "JPEG",
11043
 * "WEBP", "JXL"). This is the MIME type of one of the values
11044
 * returned by GetCompressionFormats(). The format string is designed to
11045
 * potentially include at a later point key=value optional parameters separated
11046
 * by a semi-colon character. At time of writing, none are implemented.
11047
 * ReadCompressedData() implementations should verify optional parameters and
11048
 * return CE_Failure if they cannot support one of them.
11049
 *
11050
 * @param nXOff The pixel offset to the top left corner of the region
11051
 * of the band to be accessed.  This would be zero to start from the left side.
11052
 *
11053
 * @param nYOff The line offset to the top left corner of the region
11054
 * of the band to be accessed.  This would be zero to start from the top.
11055
 *
11056
 * @param nXSize The width of the region of the band to be accessed in pixels.
11057
 *
11058
 * @param nYSize The height of the region of the band to be accessed in lines.
11059
 *
11060
 * @param nBandCount the number of bands being requested.
11061
 *
11062
 * @param panBandList the list of nBandCount band numbers.
11063
 * Note band numbers are 1 based. This may be NULL to select the first
11064
 * nBandCount bands.
11065
 *
11066
 * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11067
 * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11068
 * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11069
 * buffer will be filled with the compressed data, provided that pnBufferSize
11070
 * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11071
 * of *ppBuffer, is sufficiently large to hold the data.
11072
 * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11073
 * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11074
 * free it with VSIFree().
11075
 * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11076
 * but *pnBufferSize will be updated with an upper bound of the size that would
11077
 * be necessary to hold it (if pnBufferSize != nullptr).
11078
 *
11079
 * @param pnBufferSize Output buffer size, or nullptr.
11080
 * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11081
 * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11082
 * method is successful, *pnBufferSize will be updated with the actual size
11083
 * used.
11084
 *
11085
 * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11086
 * If ppszDetailedFormat is not nullptr, then, on success, the method will
11087
 * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11088
 * *ppszDetailedFormat might contain strings like
11089
 * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11090
 * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11091
 * The string will contain at least as much information as what
11092
 * GetCompressionFormats() returns, and potentially more when
11093
 * ppBuffer != nullptr.
11094
 *
11095
 * @return CE_None in case of success, CE_Failure otherwise.
11096
 *
11097
 * For example, to request JPEG content on the whole image and let GDAL deal
11098
 * with the buffer allocation.
11099
 * \code{.cpp}
11100
 *   void* pBuffer = nullptr;
11101
 *   size_t nBufferSize = 0;
11102
 *   CPLErr eErr =
11103
 *      poDataset->ReadCompressedData("JPEG",
11104
 *                                    0, 0,
11105
 *                                    poDataset->GetRasterXSize(),
11106
 *                                    poDataset->GetRasterYSize(),
11107
 *                                    poDataset->GetRasterCount(),
11108
 *                                    nullptr, // panBandList
11109
 *                                    &pBuffer,
11110
 *                                    &nBufferSize,
11111
 *                                    nullptr // ppszDetailedFormat
11112
 *                                   );
11113
 *   if (eErr == CE_None)
11114
 *   {
11115
 *       CPLAssert(pBuffer != nullptr);
11116
 *       CPLAssert(nBufferSize > 0);
11117
 *       VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11118
 *       if (fp)
11119
 *       {
11120
 *           VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11121
 *           VSIFCloseL(fp);
11122
 *       }
11123
 *       VSIFree(pBuffer);
11124
 *   }
11125
 * \endcode
11126
 *
11127
 * Or to manage the buffer allocation on your side:
11128
 * \code{.cpp}
11129
 *   size_t nUpperBoundBufferSize = 0;
11130
 *   CPLErr eErr =
11131
 *      poDataset->ReadCompressedData("JPEG",
11132
 *                                    0, 0,
11133
 *                                    poDataset->GetRasterXSize(),
11134
 *                                    poDataset->GetRasterYSize(),
11135
 *                                    poDataset->GetRasterCount(),
11136
 *                                    nullptr, // panBandList
11137
 *                                    nullptr, // ppBuffer,
11138
 *                                    &nUpperBoundBufferSize,
11139
 *                                    nullptr // ppszDetailedFormat
11140
 *                                   );
11141
 *   if (eErr == CE_None)
11142
 *   {
11143
 *       std::vector<uint8_t> myBuffer;
11144
 *       myBuffer.resize(nUpperBoundBufferSize);
11145
 *       void* pBuffer = myBuffer.data();
11146
 *       size_t nActualSize = nUpperBoundBufferSize;
11147
 *       char* pszDetailedFormat = nullptr;
11148
 *       // We also request detailed format, but we could have passed it to
11149
 *       // nullptr as well.
11150
 *       eErr =
11151
 *         poDataset->ReadCompressedData("JPEG",
11152
 *                                       0, 0,
11153
 *                                       poDataset->GetRasterXSize(),
11154
 *                                       poDataset->GetRasterYSize(),
11155
 *                                       poDataset->GetRasterCount(),
11156
 *                                       nullptr, // panBandList
11157
 *                                       &pBuffer,
11158
 *                                       &nActualSize,
11159
 *                                       &pszDetailedFormat);
11160
 *       if (eErr == CE_None)
11161
 *       {
11162
 *          CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11163
 *          CPLAssert(nActualSize <= nUpperBoundBufferSize);
11164
 *          myBuffer.resize(nActualSize);
11165
 *          // do something useful
11166
 *          VSIFree(pszDetailedFormat);
11167
 *       }
11168
 *   }
11169
 * \endcode
11170
 *
11171
 * @since GDAL 3.7
11172
 */
11173
CPLErr GDALDataset::ReadCompressedData(
11174
    CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11175
    CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11176
    CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11177
    CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11178
    CPL_UNUSED char **ppszDetailedFormat)
11179
0
{
11180
0
    return CE_Failure;
11181
0
}
11182
11183
/************************************************************************/
11184
/*                   GDALDatasetReadCompressedData()                    */
11185
/************************************************************************/
11186
11187
/** Return the compressed content that can be natively obtained for the
11188
 * window of interest and requested bands.
11189
 *
11190
 * For example, a tiled dataset may be able to return data in compressed format
11191
 * if the window of interest matches exactly a tile. For some formats, drivers
11192
 * may also be example to merge several tiles together (not currently
11193
 * implemented though).
11194
 *
11195
 * The implementation should make sure that the content returned forms a valid
11196
 * standalone file. For example, for the GeoTIFF implementation of this method,
11197
 * when extracting a JPEG tile, the method will automatically adds the content
11198
 * of the JPEG Huffman and/or quantization tables that might be stored in the
11199
 * TIFF JpegTables tag, and not in tile data itself.
11200
 *
11201
 * In the general case this method will return CE_Failure.
11202
 *
11203
 * This is the same as C++ method GDALDataset:ReadCompressedData().
11204
 *
11205
 * @param hDS Dataset handle.
11206
 *
11207
 * @param pszFormat Requested compression format (e.g. "JPEG",
11208
 * "WEBP", "JXL"). This is the MIME type of one of the values
11209
 * returned by GetCompressionFormats(). The format string is designed to
11210
 * potentially include at a later point key=value optional parameters separated
11211
 * by a semi-colon character. At time of writing, none are implemented.
11212
 * ReadCompressedData() implementations should verify optional parameters and
11213
 * return CE_Failure if they cannot support one of them.
11214
 *
11215
 * @param nXOff The pixel offset to the top left corner of the region
11216
 * of the band to be accessed.  This would be zero to start from the left side.
11217
 *
11218
 * @param nYOff The line offset to the top left corner of the region
11219
 * of the band to be accessed.  This would be zero to start from the top.
11220
 *
11221
 * @param nXSize The width of the region of the band to be accessed in pixels.
11222
 *
11223
 * @param nYSize The height of the region of the band to be accessed in lines.
11224
 *
11225
 * @param nBandCount the number of bands being requested.
11226
 *
11227
 * @param panBandList the list of nBandCount band numbers.
11228
 * Note band numbers are 1 based. This may be NULL to select the first
11229
 * nBandCount bands.
11230
 *
11231
 * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11232
 * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11233
 * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11234
 * buffer will be filled with the compressed data, provided that pnBufferSize
11235
 * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11236
 * of *ppBuffer, is sufficiently large to hold the data.
11237
 * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11238
 * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11239
 * free it with VSIFree().
11240
 * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11241
 * but *pnBufferSize will be updated with an upper bound of the size that would
11242
 * be necessary to hold it (if pnBufferSize != nullptr).
11243
 *
11244
 * @param pnBufferSize Output buffer size, or nullptr.
11245
 * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11246
 * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11247
 * method is successful, *pnBufferSize will be updated with the actual size
11248
 * used.
11249
 *
11250
 * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11251
 * If ppszDetailedFormat is not nullptr, then, on success, the method will
11252
 * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11253
 * *ppszDetailedFormat might contain strings like
11254
 * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11255
 * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11256
 * The string will contain at least as much information as what
11257
 * GetCompressionFormats() returns, and potentially more when
11258
 * ppBuffer != nullptr.
11259
 *
11260
 * @return CE_None in case of success, CE_Failure otherwise.
11261
 *
11262
 * @since GDAL 3.7
11263
 */
11264
CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11265
                                     int nXOff, int nYOff, int nXSize,
11266
                                     int nYSize, int nBandCount,
11267
                                     const int *panBandList, void **ppBuffer,
11268
                                     size_t *pnBufferSize,
11269
                                     char **ppszDetailedFormat)
11270
0
{
11271
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11272
0
    return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11273
0
        pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11274
0
        ppBuffer, pnBufferSize, ppszDetailedFormat);
11275
0
}
11276
11277
/************************************************************************/
11278
/*                            CanBeCloned()                             */
11279
/************************************************************************/
11280
11281
//! @cond Doxygen_Suppress
11282
11283
/** This method is called by GDALThreadSafeDataset::Create() to determine if
11284
 * it is possible to create a thread-safe wrapper for a dataset, which involves
11285
 * the ability to Clone() it.
11286
 *
11287
 * Implementations of this method must be thread-safe.
11288
 *
11289
 * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11290
 *                    expressing the intended use for thread-safety.
11291
 *                    Currently, the only valid scope is in the base
11292
 *                    implementation is GDAL_OF_RASTER.
11293
 * @param bCanShareState Determines if cloned datasets are allowed to share
11294
 *                       state with the dataset they have been cloned from.
11295
 *                       If set to true, the dataset from which they have been
11296
 *                       cloned from must remain opened during the lifetime of
11297
 *                       its clones.
11298
 * @return true if the Clone() method is expected to succeed with the same values
11299
 *         of nScopeFlags and bCanShareState.
11300
 */
11301
bool GDALDataset::CanBeCloned(int nScopeFlags,
11302
                              [[maybe_unused]] bool bCanShareState) const
11303
0
{
11304
0
    return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11305
0
}
11306
11307
//! @endcond
11308
11309
/************************************************************************/
11310
/*                               Clone()                                */
11311
/************************************************************************/
11312
11313
//! @cond Doxygen_Suppress
11314
11315
/** This method "clones" the current dataset, that is it returns a new instance
11316
 * that is opened on the same underlying "file".
11317
 *
11318
 * The base implementation uses GDALDataset::Open() to re-open the dataset.
11319
 * The MEM driver has a specialized implementation that returns a new instance,
11320
 * but which shares the same memory buffer as this.
11321
 *
11322
 * Implementations of this method must be thread-safe.
11323
 *
11324
 * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11325
 *                    expressing the intended use for thread-safety.
11326
 *                    Currently, the only valid scope is in the base
11327
 *                    implementation is GDAL_OF_RASTER.
11328
 * @param bCanShareState Determines if cloned datasets are allowed to share
11329
 *                       state with the dataset they have been cloned from.
11330
 *                       If set to true, the dataset from which they have been
11331
 *                       cloned from must remain opened during the lifetime of
11332
 *                       its clones.
11333
 * @return a new instance, or nullptr in case of error.
11334
 */
11335
std::unique_ptr<GDALDataset>
11336
GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11337
0
{
11338
0
    CPLStringList aosAllowedDrivers;
11339
0
    if (poDriver)
11340
0
        aosAllowedDrivers.AddString(poDriver->GetDescription());
11341
0
    return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11342
0
        GetDescription(),
11343
0
        nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11344
0
        aosAllowedDrivers.List(), papszOpenOptions));
11345
0
}
11346
11347
//! @endcond
11348
11349
/************************************************************************/
11350
/*                       GeolocationToPixelLine()                       */
11351
/************************************************************************/
11352
11353
/** Transform georeferenced coordinates to pixel/line coordinates.
11354
 *
11355
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11356
 * must be in the "natural" SRS of the dataset, that is the one returned by
11357
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11358
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11359
 * array (generally WGS 84) if there is a geolocation array.
11360
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11361
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11362
 * be a easting, and dfGeolocY a northing.
11363
 *
11364
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11365
 * expressed in that CRS, and that tuple must be conformant with the
11366
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11367
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11368
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11369
 * before calling this method, and in that case, dfGeolocX must be a longitude
11370
 * or an easting value, and dfGeolocX a latitude or a northing value.
11371
 *
11372
 * This method uses GDALCreateGenImgProjTransformer2() underneath.
11373
 *
11374
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11375
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11376
 * where interpolation should be done.
11377
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11378
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11379
 * where interpolation should be done.
11380
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11381
 * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11382
 * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11383
 * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11384
 *
11385
 * @return CE_None on success, or an error code on failure.
11386
 * @since GDAL 3.11
11387
 */
11388
11389
CPLErr
11390
GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11391
                                    const OGRSpatialReference *poSRS,
11392
                                    double *pdfPixel, double *pdfLine,
11393
                                    CSLConstList papszTransformerOptions) const
11394
0
{
11395
0
    CPLStringList aosTO(papszTransformerOptions);
11396
11397
0
    if (poSRS)
11398
0
    {
11399
0
        const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11400
0
        const std::string osWKT = poSRS->exportToWkt(apszOptions);
11401
0
        aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11402
0
        const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11403
0
        if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11404
0
            aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11405
0
                               "TRADITIONAL_GIS_ORDER");
11406
0
        else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11407
0
            aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11408
0
                               "AUTHORITY_COMPLIANT");
11409
0
        else
11410
0
        {
11411
0
            const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11412
0
            std::string osVal;
11413
0
            for (int v : anValues)
11414
0
            {
11415
0
                if (!osVal.empty())
11416
0
                    osVal += ',';
11417
0
                osVal += std::to_string(v);
11418
0
            }
11419
0
            aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11420
0
                               osVal.c_str());
11421
0
        }
11422
0
    }
11423
11424
0
    auto hTransformer = GDALCreateGenImgProjTransformer2(
11425
0
        GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11426
0
        aosTO.List());
11427
0
    if (hTransformer == nullptr)
11428
0
    {
11429
0
        return CE_Failure;
11430
0
    }
11431
11432
0
    double z = 0;
11433
0
    int bSuccess = 0;
11434
0
    GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11435
0
                            &bSuccess);
11436
0
    GDALDestroyTransformer(hTransformer);
11437
0
    if (bSuccess)
11438
0
    {
11439
0
        if (pdfPixel)
11440
0
            *pdfPixel = dfGeolocX;
11441
0
        if (pdfLine)
11442
0
            *pdfLine = dfGeolocY;
11443
0
        return CE_None;
11444
0
    }
11445
0
    else
11446
0
    {
11447
0
        return CE_Failure;
11448
0
    }
11449
0
}
11450
11451
/************************************************************************/
11452
/*                 GDALDatasetGeolocationToPixelLine()                  */
11453
/************************************************************************/
11454
11455
/** Transform georeferenced coordinates to pixel/line coordinates.
11456
 *
11457
 * @see GDALDataset::GeolocationToPixelLine()
11458
 * @since GDAL 3.11
11459
 */
11460
11461
CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11462
                                         double dfGeolocY,
11463
                                         OGRSpatialReferenceH hSRS,
11464
                                         double *pdfPixel, double *pdfLine,
11465
                                         CSLConstList papszTransformerOptions)
11466
0
{
11467
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11468
11469
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11470
0
    return poDS->GeolocationToPixelLine(
11471
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11472
0
        pdfLine, papszTransformerOptions);
11473
0
}
11474
11475
/************************************************************************/
11476
/*                             GetExtent()                              */
11477
/************************************************************************/
11478
11479
/** Return extent of dataset in specified CRS.
11480
 *
11481
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11482
 *
11483
 * For rasters, the base implementation of this method only succeeds if
11484
 * GetGeoTransform() and GetSpatialRef() succeed.
11485
 * For vectors, the base implementation of this method iterates over layers
11486
 * and call their OGRLayer::GetExtent() method.
11487
 *
11488
 * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11489
 * time of this method is fast.
11490
 *
11491
 * This is the same as C function GDALGetExtent()
11492
 *
11493
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11494
 * @param poCRS CRS in which to express the extent. If not specified, this will
11495
 * be the raster CRS or the CRS of the first layer for a vector dataset.
11496
 * @return CE_None in case of success, CE_Failure otherwise
11497
 * @since GDAL 3.12
11498
 */
11499
11500
CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11501
                              const OGRSpatialReference *poCRS) const
11502
0
{
11503
0
    const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11504
0
    int nLayerCount = 0;
11505
0
    if (!poThisCRS)
11506
0
    {
11507
0
        nLayerCount = GetLayerCount();
11508
0
        if (nLayerCount >= 1)
11509
0
        {
11510
0
            if (auto poLayer = GetLayer(0))
11511
0
                poThisCRS = poLayer->GetSpatialRef();
11512
0
        }
11513
0
    }
11514
0
    if (!poCRS)
11515
0
        poCRS = poThisCRS;
11516
0
    else if (!poThisCRS)
11517
0
        return CE_Failure;
11518
11519
0
    *psExtent = OGREnvelope();
11520
11521
0
    GDALGeoTransform gt;
11522
0
    auto poThisDS = const_cast<GDALDataset *>(this);
11523
0
    const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11524
0
    if (bHasGT)
11525
0
    {
11526
0
        std::unique_ptr<OGRCoordinateTransformation> poCT;
11527
0
        if (poCRS)
11528
0
        {
11529
0
            poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11530
0
        }
11531
11532
0
        constexpr int DENSIFY_POINT_COUNT = 21;
11533
0
        double dfULX = gt.xorig;
11534
0
        double dfULY = gt.yorig;
11535
0
        double dfURX = 0, dfURY = 0;
11536
0
        gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11537
0
        double dfLLX = 0, dfLLY = 0;
11538
0
        gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11539
0
        double dfLRX = 0, dfLRY = 0;
11540
0
        gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11541
0
        const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11542
0
        const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11543
0
        const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11544
0
        const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11545
0
        if (poCT)
11546
0
        {
11547
0
            OGREnvelope sEnvTmp;
11548
0
            if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11549
0
                                       &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11550
0
                                       &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11551
0
            {
11552
0
                return CE_Failure;
11553
0
            }
11554
0
            *psExtent = sEnvTmp;
11555
0
        }
11556
0
        else
11557
0
        {
11558
0
            psExtent->MinX = xmin;
11559
0
            psExtent->MinY = ymin;
11560
0
            psExtent->MaxX = xmax;
11561
0
            psExtent->MaxY = ymax;
11562
0
        }
11563
0
    }
11564
11565
0
    if (nLayerCount > 0)
11566
0
    {
11567
0
        for (auto &&poLayer : poThisDS->GetLayers())
11568
0
        {
11569
0
            auto poLayerCRS = poLayer->GetSpatialRef();
11570
0
            if (poLayerCRS)
11571
0
            {
11572
0
                OGREnvelope sLayerExtent;
11573
0
                if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11574
0
                {
11575
0
                    auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11576
0
                        OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11577
0
                    if (poCT)
11578
0
                    {
11579
0
                        constexpr int DENSIFY_POINT_COUNT = 21;
11580
0
                        OGREnvelope sEnvTmp;
11581
0
                        if (poCT->TransformBounds(
11582
0
                                sLayerExtent.MinX, sLayerExtent.MinY,
11583
0
                                sLayerExtent.MaxX, sLayerExtent.MaxY,
11584
0
                                &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11585
0
                                &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11586
0
                                DENSIFY_POINT_COUNT))
11587
0
                        {
11588
0
                            psExtent->Merge(sEnvTmp);
11589
0
                        }
11590
0
                    }
11591
0
                }
11592
0
            }
11593
0
        }
11594
0
    }
11595
11596
0
    return psExtent->IsInit() ? CE_None : CE_Failure;
11597
0
}
11598
11599
/************************************************************************/
11600
/*                           GDALGetExtent()                            */
11601
/************************************************************************/
11602
11603
/** Return extent of dataset in specified CRS.
11604
 *
11605
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11606
 *
11607
 * For rasters, the base implementation of this method only succeeds if
11608
 * GetGeoTransform() and GetSpatialRef() succeed.
11609
 * For vectors, the base implementation of this method iterates over layers
11610
 * and call their OGRLayer::GetExtent() method.
11611
 *
11612
 * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11613
 * time of this method is fast.
11614
 *
11615
 * This is the same as C++ method GDALDataset::GetExtent()
11616
 *
11617
 * @param hDS Dataset handle. Must NOT be null.
11618
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11619
 * @param hCRS CRS in which to express the extent. If not specified, this will
11620
 * be the raster CRS or the CRS of the first layer for a vector dataset.
11621
 * @return extent in poCRS (valid only if IsInit() method returns true)
11622
 * @since GDAL 3.12
11623
 */
11624
11625
CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11626
                     OGRSpatialReferenceH hCRS)
11627
0
{
11628
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11629
0
    VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11630
0
    return GDALDataset::FromHandle(hDS)->GetExtent(
11631
0
        psExtent, OGRSpatialReference::FromHandle(hCRS));
11632
0
}
11633
11634
/************************************************************************/
11635
/*                       GetExtentWGS84LongLat()                        */
11636
/************************************************************************/
11637
11638
/** Return extent of dataset in WGS84 longitude/latitude
11639
 *
11640
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11641
 *
11642
 * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11643
 * time of this method is fast.
11644
 *
11645
 * This is the same as C function GDALGetExtentWGS84LongLat()
11646
 *
11647
 * @return extent (valid only if IsInit() method returns true)
11648
 * @since GDAL 3.12
11649
 */
11650
11651
CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11652
0
{
11653
0
    OGRSpatialReference oSRS_WGS84;
11654
0
    oSRS_WGS84.SetFromUserInput("WGS84");
11655
0
    oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11656
0
    return GetExtent(psExtent, &oSRS_WGS84);
11657
0
}
11658
11659
/************************************************************************/
11660
/*                     GDALGetExtentWGS84LongLat()                      */
11661
/************************************************************************/
11662
11663
/** Return extent of dataset in WGS84 longitude/latitude
11664
 *
11665
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11666
 *
11667
 * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11668
 * time of this method is fast.
11669
 *
11670
 * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11671
 *
11672
 * @param hDS Dataset handle. Must NOT be null.
11673
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11674
 * @return extent (valid only if IsInit() method returns true)
11675
 * @since GDAL 3.12
11676
 */
11677
11678
CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11679
0
{
11680
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11681
0
    VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11682
0
    return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11683
0
}
11684
11685
/************************************************************************/
11686
/*                  ReportUpdateNotSupportedByDriver()                  */
11687
/************************************************************************/
11688
11689
//! @cond Doxygen_Suppress
11690
11691
/* static */
11692
void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11693
0
{
11694
0
    CPLError(CE_Failure, CPLE_NotSupported,
11695
0
             "The %s driver does not support update access to existing "
11696
0
             "datasets.",
11697
0
             pszDriverName);
11698
0
}
11699
11700
//! @endcond
11701
11702
/************************************************************************/
11703
/*                           BuildFilename()                            */
11704
/************************************************************************/
11705
11706
/** Generates a filename, potentially relative to another one.
11707
 *
11708
 * Given the path to a reference directory, and a path to a file
11709
 * referenced from it, build a path to the file that the current application
11710
 * can use. If the file path is already absolute, rather than relative, or if
11711
 * bRelativeToReferencePath is false, then the filename of interest will be
11712
 * returned unaltered.
11713
 *
11714
 * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11715
 * into account the subdataset syntax.
11716
 *
11717
 * Examples:
11718
 * \code{.cpp}
11719
 * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11720
 * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11721
 * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11722
 * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11723
 * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11724
 * \endcode
11725
 *
11726
 * @param pszFilename Filename of interest.
11727
 * @param pszReferencePath Path to a reference directory.
11728
 * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11729
 *                                 relative to pszReferencePath
11730
 * @since 3.11
11731
 */
11732
11733
/* static */
11734
std::string GDALDataset::BuildFilename(const char *pszFilename,
11735
                                       const char *pszReferencePath,
11736
                                       bool bRelativeToReferencePath)
11737
0
{
11738
0
    std::string osSrcDSName;
11739
0
    if (pszReferencePath != nullptr && bRelativeToReferencePath)
11740
0
    {
11741
        // Try subdatasetinfo API first
11742
        // Note: this will become the only branch when subdatasetinfo will become
11743
        //       available for NITF_IM, RASTERLITE and TILEDB
11744
0
        const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11745
0
        if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11746
0
        {
11747
0
            auto path{oSubDSInfo->GetPathComponent()};
11748
0
            osSrcDSName = oSubDSInfo->ModifyPathComponent(
11749
0
                CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11750
0
                    .c_str());
11751
0
            GDALDestroySubdatasetInfo(oSubDSInfo);
11752
0
        }
11753
0
        else
11754
0
        {
11755
0
            bool bDone = false;
11756
0
            for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11757
0
            {
11758
0
                CPLString osPrefix(pszSyntax);
11759
0
                osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11760
0
                if (pszSyntax[osPrefix.size()] == '"')
11761
0
                    osPrefix += '"';
11762
0
                if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11763
0
                {
11764
0
                    if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11765
0
                    {
11766
0
                        const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11767
                        // CSV:z:/foo.xyz
11768
0
                        if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11769
0
                            pszLastPart - pszFilename >= 3 &&
11770
0
                            pszLastPart[-3] == ':')
11771
0
                        {
11772
0
                            pszLastPart -= 2;
11773
0
                        }
11774
0
                        CPLString osPrefixFilename = pszFilename;
11775
0
                        osPrefixFilename.resize(pszLastPart - pszFilename);
11776
0
                        osSrcDSName = osPrefixFilename +
11777
0
                                      CPLProjectRelativeFilenameSafe(
11778
0
                                          pszReferencePath, pszLastPart);
11779
0
                        bDone = true;
11780
0
                    }
11781
0
                    else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11782
0
                                            "{FILENAME}"))
11783
0
                    {
11784
0
                        CPLString osFilename(pszFilename + osPrefix.size());
11785
0
                        size_t nPos = 0;
11786
0
                        if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11787
0
                            (osFilename[2] == '\\' || osFilename[2] == '/'))
11788
0
                            nPos = 2;
11789
0
                        nPos = osFilename.find(
11790
0
                            pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11791
0
                            nPos);
11792
0
                        if (nPos != std::string::npos)
11793
0
                        {
11794
0
                            const CPLString osSuffix = osFilename.substr(nPos);
11795
0
                            osFilename.resize(nPos);
11796
0
                            osSrcDSName = osPrefix +
11797
0
                                          CPLProjectRelativeFilenameSafe(
11798
0
                                              pszReferencePath, osFilename) +
11799
0
                                          osSuffix;
11800
0
                            bDone = true;
11801
0
                        }
11802
0
                    }
11803
0
                    break;
11804
0
                }
11805
0
            }
11806
0
            if (!bDone)
11807
0
            {
11808
0
                std::string osReferencePath = pszReferencePath;
11809
0
                if (!CPLIsFilenameRelative(pszReferencePath))
11810
0
                {
11811
                    // Simplify path by replacing "foo/a/../b" with "foo/b"
11812
0
                    while (STARTS_WITH(pszFilename, "../"))
11813
0
                    {
11814
0
                        osReferencePath =
11815
0
                            CPLGetPathSafe(osReferencePath.c_str());
11816
0
                        pszFilename += strlen("../");
11817
0
                    }
11818
0
                }
11819
11820
0
                osSrcDSName = CPLProjectRelativeFilenameSafe(
11821
0
                    osReferencePath.c_str(), pszFilename);
11822
0
            }
11823
0
        }
11824
0
    }
11825
0
    else
11826
0
    {
11827
0
        osSrcDSName = pszFilename;
11828
0
    }
11829
0
    return osSrcDSName;
11830
0
}
11831
11832
/************************************************************************/
11833
/*                        GDALMDArrayFromDataset                        */
11834
/************************************************************************/
11835
11836
class GDALMDArrayFromDataset final : public GDALMDArray
11837
{
11838
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11839
11840
    GDALDataset *const m_poDS;
11841
    const GDALExtendedDataType m_dt;
11842
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11843
    std::string m_osUnit{};
11844
    std::vector<GByte> m_abyNoData{};
11845
    std::shared_ptr<GDALMDArray> m_varX{};
11846
    std::shared_ptr<GDALMDArray> m_varY{};
11847
    std::shared_ptr<GDALMDArray> m_varBand{};
11848
    const std::string m_osFilename;
11849
    const CPLStringList m_aosOptions;
11850
    int m_iBandDim = 0;
11851
    int m_iYDim = 1;
11852
    int m_iXDim = 2;
11853
    mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11854
11855
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11856
                   const size_t *count, const GInt64 *arrayStep,
11857
                   const GPtrDiff_t *bufferStride,
11858
                   const GDALExtendedDataType &bufferDataType,
11859
                   void *pBuffer) const;
11860
11861
  protected:
11862
    GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11863
0
        : GDALAbstractMDArray(std::string(),
11864
0
                              std::string(poDS->GetDescription())),
11865
0
          GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11866
0
          m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11867
0
                            poDS->GetRasterBand(1)->GetRasterDataType())),
11868
0
          m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11869
0
    {
11870
0
        m_poDS->Reference();
11871
11872
0
        const int nBandCount = poDS->GetRasterCount();
11873
0
        for (int i = 1; i <= nBandCount; ++i)
11874
0
        {
11875
0
            const auto poBand = poDS->GetRasterBand(i);
11876
0
            if (i == 1)
11877
0
                m_osUnit = poBand->GetUnitType();
11878
0
            else if (m_osUnit != poBand->GetUnitType())
11879
0
                m_osUnit.clear();
11880
11881
0
            std::vector<GByte> abyNoData;
11882
0
            int bHasNoData = false;
11883
0
            switch (poBand->GetRasterDataType())
11884
0
            {
11885
0
                case GDT_Int64:
11886
0
                {
11887
0
                    const auto nNoData =
11888
0
                        poBand->GetNoDataValueAsInt64(&bHasNoData);
11889
0
                    if (bHasNoData)
11890
0
                    {
11891
0
                        abyNoData.resize(m_dt.GetSize());
11892
0
                        GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11893
0
                                        m_dt.GetNumericDataType(), 0, 1);
11894
0
                    }
11895
0
                    break;
11896
0
                }
11897
11898
0
                case GDT_UInt64:
11899
0
                {
11900
0
                    const auto nNoData =
11901
0
                        poBand->GetNoDataValueAsUInt64(&bHasNoData);
11902
0
                    if (bHasNoData)
11903
0
                    {
11904
0
                        abyNoData.resize(m_dt.GetSize());
11905
0
                        GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11906
0
                                        m_dt.GetNumericDataType(), 0, 1);
11907
0
                    }
11908
0
                    break;
11909
0
                }
11910
11911
0
                default:
11912
0
                {
11913
0
                    const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11914
0
                    if (bHasNoData)
11915
0
                    {
11916
0
                        abyNoData.resize(m_dt.GetSize());
11917
0
                        GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11918
0
                                        &abyNoData[0],
11919
0
                                        m_dt.GetNumericDataType(), 0, 1);
11920
0
                    }
11921
0
                    break;
11922
0
                }
11923
0
            }
11924
11925
0
            if (i == 1)
11926
0
                m_abyNoData = std::move(abyNoData);
11927
0
            else if (m_abyNoData != abyNoData)
11928
0
                m_abyNoData.clear();
11929
0
        }
11930
11931
0
        const int nXSize = poDS->GetRasterXSize();
11932
0
        const int nYSize = poDS->GetRasterYSize();
11933
11934
0
        auto poSRS = poDS->GetSpatialRef();
11935
0
        std::string osTypeY;
11936
0
        std::string osTypeX;
11937
0
        std::string osDirectionY;
11938
0
        std::string osDirectionX;
11939
0
        if (poSRS && poSRS->GetAxesCount() == 2)
11940
0
        {
11941
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11942
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
11943
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
11944
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
11945
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
11946
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11947
0
            {
11948
0
                if (mapping == std::vector<int>{1, 2})
11949
0
                {
11950
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11951
0
                    osDirectionY = "NORTH";
11952
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11953
0
                    osDirectionX = "EAST";
11954
0
                }
11955
0
            }
11956
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11957
0
            {
11958
0
                if (mapping == std::vector<int>{2, 1})
11959
0
                {
11960
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11961
0
                    osDirectionY = "NORTH";
11962
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11963
0
                    osDirectionX = "EAST";
11964
0
                }
11965
0
            }
11966
0
        }
11967
11968
0
        const bool bBandYX = [papszOptions, poDS, nBandCount]()
11969
0
        {
11970
0
            const char *pszDimOrder =
11971
0
                CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11972
0
            if (EQUAL(pszDimOrder, "AUTO"))
11973
0
            {
11974
0
                const char *pszInterleave =
11975
0
                    poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11976
0
                return nBandCount == 1 || !pszInterleave ||
11977
0
                       !EQUAL(pszInterleave, "PIXEL");
11978
0
            }
11979
0
            else
11980
0
            {
11981
0
                return EQUAL(pszDimOrder, "BAND,Y,X");
11982
0
            }
11983
0
        }();
11984
0
        const char *const pszBandDimName =
11985
0
            CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11986
0
        auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11987
0
            "/", pszBandDimName, std::string(), std::string(), nBandCount);
11988
0
        const char *const pszYDimName =
11989
0
            CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11990
0
        auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11991
0
            "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11992
0
        const char *const pszXDimName =
11993
0
            CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11994
0
        auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11995
0
            "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11996
11997
0
        const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11998
0
            papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
11999
0
        if (EQUAL(pszBandIndexingVarItem, "{Description}"))
12000
0
        {
12001
0
            const auto oIndexingVarType =
12002
0
                GDALExtendedDataType::CreateString(strlen("Band 65535"));
12003
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12004
0
                                                {poBandDim}, oIndexingVarType);
12005
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12006
0
            for (int i = 0; i < nBandCount; ++i)
12007
0
            {
12008
0
                const char *pszDesc =
12009
0
                    poDS->GetRasterBand(i + 1)->GetDescription();
12010
0
                const std::string osBandName =
12011
0
                    pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
12012
0
                const char *pszBandName = osBandName.c_str();
12013
0
                const char *const apszBandVal[] = {pszBandName};
12014
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12015
0
                const size_t anCount[] = {1};
12016
0
                const GInt64 arrayStep[] = {1};
12017
0
                const GPtrDiff_t anBufferStride[] = {1};
12018
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12019
0
                                 oIndexingVarType, apszBandVal);
12020
0
            }
12021
0
            m_varBand = std::move(poBandVar);
12022
0
            poBandDim->SetIndexingVariable(m_varBand);
12023
0
        }
12024
0
        else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
12025
0
        {
12026
0
            const auto oIndexingVarType =
12027
0
                GDALExtendedDataType::Create(GDT_Int32);
12028
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12029
0
                                                {poBandDim}, oIndexingVarType);
12030
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12031
0
            for (int i = 0; i < nBandCount; ++i)
12032
0
            {
12033
0
                const int anBandIdx[] = {i + 1};
12034
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12035
0
                const size_t anCount[] = {1};
12036
0
                const GInt64 arrayStep[] = {1};
12037
0
                const GPtrDiff_t anBufferStride[] = {1};
12038
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12039
0
                                 oIndexingVarType, anBandIdx);
12040
0
            }
12041
0
            m_varBand = std::move(poBandVar);
12042
0
            poBandDim->SetIndexingVariable(m_varBand);
12043
0
        }
12044
0
        else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
12045
0
        {
12046
0
            size_t nMaxLen = 0;
12047
0
            for (int i = 0; i < nBandCount; ++i)
12048
0
            {
12049
0
                const char *pszDesc = GDALGetColorInterpretationName(
12050
0
                    poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12051
0
                nMaxLen = std::max(nMaxLen, strlen(pszDesc));
12052
0
            }
12053
0
            const auto oIndexingVarType =
12054
0
                GDALExtendedDataType::CreateString(nMaxLen);
12055
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12056
0
                                                {poBandDim}, oIndexingVarType);
12057
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12058
0
            for (int i = 0; i < nBandCount; ++i)
12059
0
            {
12060
0
                const char *pszDesc = GDALGetColorInterpretationName(
12061
0
                    poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12062
0
                const char *const apszBandVal[] = {pszDesc};
12063
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12064
0
                const size_t anCount[] = {1};
12065
0
                const GInt64 arrayStep[] = {1};
12066
0
                const GPtrDiff_t anBufferStride[] = {1};
12067
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12068
0
                                 oIndexingVarType, apszBandVal);
12069
0
            }
12070
0
            m_varBand = std::move(poBandVar);
12071
0
            poBandDim->SetIndexingVariable(m_varBand);
12072
0
        }
12073
0
        else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
12074
0
        {
12075
0
            const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
12076
0
                papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
12077
0
            size_t nMaxLen = 0;
12078
0
            if (EQUAL(pszBandIndexingVarType, "String"))
12079
0
            {
12080
0
                for (int i = 0; i < nBandCount; ++i)
12081
0
                {
12082
0
                    const char *pszVal =
12083
0
                        poDS->GetRasterBand(i + 1)->GetMetadataItem(
12084
0
                            pszBandIndexingVarItem);
12085
0
                    if (pszVal)
12086
0
                        nMaxLen = std::max(nMaxLen, strlen(pszVal));
12087
0
                }
12088
0
            }
12089
0
            const auto oIndexingVarType =
12090
0
                EQUAL(pszBandIndexingVarType, "String")
12091
0
                    ? GDALExtendedDataType::CreateString(nMaxLen)
12092
0
                : EQUAL(pszBandIndexingVarType, "Integer")
12093
0
                    ? GDALExtendedDataType::Create(GDT_Int32)
12094
0
                    : GDALExtendedDataType::Create(GDT_Float64);
12095
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12096
0
                                                {poBandDim}, oIndexingVarType);
12097
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12098
0
            for (int i = 0; i < nBandCount; ++i)
12099
0
            {
12100
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12101
0
                const size_t anCount[] = {1};
12102
0
                const GInt64 arrayStep[] = {1};
12103
0
                const GPtrDiff_t anBufferStride[] = {1};
12104
0
                const char *pszVal =
12105
0
                    poDS->GetRasterBand(i + 1)->GetMetadataItem(
12106
0
                        pszBandIndexingVarItem);
12107
0
                if (oIndexingVarType.GetClass() == GEDTC_STRING)
12108
0
                {
12109
0
                    const char *const apszBandVal[] = {pszVal ? pszVal : ""};
12110
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12111
0
                                     anBufferStride, oIndexingVarType,
12112
0
                                     apszBandVal);
12113
0
                }
12114
0
                else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12115
0
                {
12116
0
                    const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12117
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12118
0
                                     anBufferStride, oIndexingVarType, anVal);
12119
0
                }
12120
0
                else
12121
0
                {
12122
0
                    const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12123
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12124
0
                                     anBufferStride, oIndexingVarType, adfVal);
12125
0
                }
12126
0
            }
12127
0
            m_varBand = std::move(poBandVar);
12128
0
            poBandDim->SetIndexingVariable(m_varBand);
12129
0
        }
12130
12131
0
        GDALGeoTransform gt;
12132
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12133
0
        {
12134
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
12135
0
                "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12136
0
            poXDim->SetIndexingVariable(m_varX);
12137
12138
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
12139
0
                "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12140
0
            poYDim->SetIndexingVariable(m_varY);
12141
0
        }
12142
0
        if (bBandYX)
12143
0
        {
12144
0
            m_dims = {std::move(poBandDim), std::move(poYDim),
12145
0
                      std::move(poXDim)};
12146
0
        }
12147
0
        else
12148
0
        {
12149
0
            m_iYDim = 0;
12150
0
            m_iXDim = 1;
12151
0
            m_iBandDim = 2;
12152
0
            m_dims = {std::move(poYDim), std::move(poXDim),
12153
0
                      std::move(poBandDim)};
12154
0
        }
12155
0
    }
12156
12157
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12158
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12159
               const GDALExtendedDataType &bufferDataType,
12160
               void *pDstBuffer) const override;
12161
12162
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12163
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12164
                const GDALExtendedDataType &bufferDataType,
12165
                const void *pSrcBuffer) override
12166
0
    {
12167
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12168
0
                         bufferStride, bufferDataType,
12169
0
                         const_cast<void *>(pSrcBuffer));
12170
0
    }
12171
12172
  public:
12173
    ~GDALMDArrayFromDataset() override
12174
0
    {
12175
0
        m_poDS->ReleaseRef();
12176
0
    }
12177
12178
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12179
                                               CSLConstList papszOptions)
12180
0
    {
12181
0
        auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12182
0
            new GDALMDArrayFromDataset(poDS, papszOptions)));
12183
0
        array->SetSelf(array);
12184
0
        return array;
12185
0
    }
12186
12187
    bool IsWritable() const override
12188
0
    {
12189
0
        return m_poDS->GetAccess() == GA_Update;
12190
0
    }
12191
12192
    const std::string &GetFilename() const override
12193
0
    {
12194
0
        return m_osFilename;
12195
0
    }
12196
12197
    const std::vector<std::shared_ptr<GDALDimension>> &
12198
    GetDimensions() const override
12199
0
    {
12200
0
        return m_dims;
12201
0
    }
12202
12203
    const GDALExtendedDataType &GetDataType() const override
12204
0
    {
12205
0
        return m_dt;
12206
0
    }
12207
12208
    const std::string &GetUnit() const override
12209
0
    {
12210
0
        return m_osUnit;
12211
0
    }
12212
12213
    const void *GetRawNoDataValue() const override
12214
0
    {
12215
0
        return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12216
0
    }
12217
12218
    double GetOffset(bool *pbHasOffset,
12219
                     GDALDataType *peStorageType) const override
12220
0
    {
12221
0
        double dfRes = 0;
12222
0
        int bHasOffset = false;
12223
0
        auto poFirstBand = m_poDS->GetRasterBand(1);
12224
0
        if (poFirstBand)  // to avoid -Wnull-dereference
12225
0
        {
12226
0
            dfRes = poFirstBand->GetOffset(&bHasOffset);
12227
0
            for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12228
0
            {
12229
0
                const double dfOtherRes =
12230
0
                    m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12231
0
                bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12232
0
            }
12233
0
        }
12234
0
        if (pbHasOffset)
12235
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12236
0
        if (peStorageType)
12237
0
            *peStorageType = GDT_Unknown;
12238
0
        return dfRes;
12239
0
    }
12240
12241
    double GetScale(bool *pbHasScale,
12242
                    GDALDataType *peStorageType) const override
12243
0
    {
12244
0
        double dfRes = 0;
12245
0
        int bHasScale = false;
12246
0
        auto poFirstBand = m_poDS->GetRasterBand(1);
12247
0
        if (poFirstBand)  // to avoid -Wnull-dereference
12248
0
        {
12249
0
            dfRes = poFirstBand->GetScale(&bHasScale);
12250
0
            for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12251
0
            {
12252
0
                const double dfOtherRes =
12253
0
                    m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12254
0
                bHasScale = bHasScale && (dfOtherRes == dfRes);
12255
0
            }
12256
0
        }
12257
0
        if (pbHasScale)
12258
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
12259
0
        if (peStorageType)
12260
0
            *peStorageType = GDT_Unknown;
12261
0
        return dfRes;
12262
0
    }
12263
12264
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12265
0
    {
12266
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
12267
0
        if (!poSrcSRS)
12268
0
            return nullptr;
12269
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12270
12271
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12272
0
        for (auto &m : axisMapping)
12273
0
        {
12274
0
            if (m == 1)
12275
0
                m = m_iXDim + 1;
12276
0
            else if (m == 2)
12277
0
                m = m_iYDim + 1;
12278
0
            else
12279
0
                m = 0;
12280
0
        }
12281
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12282
0
        return poSRS;
12283
0
    }
12284
12285
    std::vector<GUInt64> GetBlockSize() const override
12286
0
    {
12287
0
        int nBlockXSize = 0;
12288
0
        int nBlockYSize = 0;
12289
0
        m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12290
0
        if (m_iBandDim == 0)
12291
0
        {
12292
0
            return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12293
0
                                        static_cast<GUInt64>(nBlockXSize)};
12294
0
        }
12295
0
        else
12296
0
        {
12297
0
            return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12298
0
                                        static_cast<GUInt64>(nBlockXSize), 1};
12299
0
        }
12300
0
    }
12301
12302
    std::vector<std::shared_ptr<GDALAttribute>>
12303
    GetAttributes(CSLConstList) const override
12304
0
    {
12305
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
12306
0
        auto papszMD = m_poDS->GetMetadata();
12307
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
12308
0
        {
12309
0
            char *pszKey = nullptr;
12310
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12311
0
            if (pszKey && pszValue)
12312
0
            {
12313
0
                res.emplace_back(
12314
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12315
0
            }
12316
0
            CPLFree(pszKey);
12317
0
        }
12318
0
        return res;
12319
0
    }
12320
12321
    int GetOverviewCount() const override
12322
0
    {
12323
0
        int nOvrCount = 0;
12324
0
        GDALDataset *poOvrDS = nullptr;
12325
0
        bool bOK = true;
12326
0
        for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12327
0
        {
12328
0
            auto poBand = m_poDS->GetRasterBand(i);
12329
0
            const int nThisOvrCount = poBand->GetOverviewCount();
12330
0
            bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12331
0
            if (bOK)
12332
0
            {
12333
0
                nOvrCount = nThisOvrCount;
12334
0
                auto poFirstOvrBand = poBand->GetOverview(0);
12335
0
                bOK = poFirstOvrBand != nullptr;
12336
0
                if (bOK)
12337
0
                {
12338
0
                    auto poThisOvrDS = poFirstOvrBand->GetDataset();
12339
0
                    bOK = poThisOvrDS != nullptr &&
12340
0
                          poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12341
0
                          (i == 1 || poThisOvrDS == poOvrDS);
12342
0
                    if (bOK)
12343
0
                        poOvrDS = poThisOvrDS;
12344
0
                }
12345
0
            }
12346
0
        }
12347
0
        return bOK ? nOvrCount : 0;
12348
0
    }
12349
12350
    std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12351
0
    {
12352
0
        const int nOverviews = GetOverviewCount();
12353
0
        if (idx < 0 || idx >= nOverviews)
12354
0
            return nullptr;
12355
0
        m_apoOverviews.resize(nOverviews);
12356
0
        if (!m_apoOverviews[idx])
12357
0
        {
12358
0
            if (auto poBand = m_poDS->GetRasterBand(1))
12359
0
            {
12360
0
                if (auto poOvrBand = poBand->GetOverview(idx))
12361
0
                {
12362
0
                    if (auto poOvrDS = poOvrBand->GetDataset())
12363
0
                    {
12364
0
                        m_apoOverviews[idx] =
12365
0
                            Create(poOvrDS, m_aosOptions.List());
12366
0
                    }
12367
0
                }
12368
0
            }
12369
0
        }
12370
0
        return m_apoOverviews[idx];
12371
0
    }
12372
};
12373
12374
bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12375
                                   const size_t *count, const GInt64 *arrayStep,
12376
                                   const GPtrDiff_t *bufferStride,
12377
                                   const GDALExtendedDataType &bufferDataType,
12378
                                   void *pDstBuffer) const
12379
0
{
12380
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12381
0
                     bufferDataType, pDstBuffer);
12382
0
}
12383
12384
/************************************************************************/
12385
/*                             ReadWrite()                              */
12386
/************************************************************************/
12387
12388
bool GDALMDArrayFromDataset::ReadWrite(
12389
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12390
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12391
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12392
0
{
12393
0
    const auto eDT(bufferDataType.GetNumericDataType());
12394
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12395
0
    const int nX =
12396
0
        arrayStep[m_iXDim] > 0
12397
0
            ? static_cast<int>(arrayStartIdx[m_iXDim])
12398
0
            : static_cast<int>(arrayStartIdx[m_iXDim] -
12399
0
                               (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12400
0
    const int nY =
12401
0
        arrayStep[m_iYDim] > 0
12402
0
            ? static_cast<int>(arrayStartIdx[m_iYDim])
12403
0
            : static_cast<int>(arrayStartIdx[m_iYDim] -
12404
0
                               (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12405
0
    const int nSizeX =
12406
0
        static_cast<int>(count[m_iXDim] * std::abs(arrayStep[m_iXDim]));
12407
0
    const int nSizeY =
12408
0
        static_cast<int>(count[m_iYDim] * std::abs(arrayStep[m_iYDim]));
12409
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12410
0
    int nStrideXSign = 1;
12411
0
    if (arrayStep[m_iXDim] < 0)
12412
0
    {
12413
0
        pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12414
0
        nStrideXSign = -1;
12415
0
    }
12416
0
    int nStrideYSign = 1;
12417
0
    if (arrayStep[m_iYDim] < 0)
12418
0
    {
12419
0
        pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12420
0
        nStrideYSign = -1;
12421
0
    }
12422
0
    const GSpacing nPixelSpace =
12423
0
        static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12424
0
    const GSpacing nLineSpace =
12425
0
        static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12426
0
    const GSpacing nBandSpace =
12427
0
        static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12428
0
    std::vector<int> anBandList;
12429
0
    for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12430
0
        anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12431
0
                             i * static_cast<int>(arrayStep[m_iBandDim]));
12432
12433
0
    return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12434
0
                            static_cast<int>(count[m_iXDim]),
12435
0
                            static_cast<int>(count[m_iYDim]), eDT,
12436
0
                            static_cast<int>(count[m_iBandDim]),
12437
0
                            anBandList.data(), nPixelSpace, nLineSpace,
12438
0
                            nBandSpace, nullptr) == CE_None;
12439
0
}
12440
12441
/************************************************************************/
12442
/*                             AsMDArray()                              */
12443
/************************************************************************/
12444
12445
/** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12446
 *
12447
 * If this dataset is not already marked as shared, it will be, so that the
12448
 * returned array holds a reference to it.
12449
 *
12450
 * If the dataset has a geotransform attached, the X and Y dimensions of the
12451
 * returned array will have an associated indexing variable.
12452
 *
12453
 * The currently supported list of options is:
12454
 * <ul>
12455
 * <li>DIM_ORDER=&lt;order&gt; where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12456
 * "Band,Y,X" means that the first (slowest changing) dimension is Band
12457
 * and the last (fastest changing direction) is X
12458
 * "Y,X,Band" means that the first (slowest changing) dimension is Y
12459
 * and the last (fastest changing direction) is Band.
12460
 * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12461
 * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12462
 * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12463
 * "Y,X,Band" is use.
12464
 * </li>
12465
 * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|&lt;BandMetadataItem&gt;:
12466
 * item from which to build the band indexing variable.
12467
 * <ul>
12468
 * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12469
 * <li>"{None}" means that no band indexing variable must be created.</li>
12470
 * <li>"{Index}" means that the band index (starting at one) is used.</li>
12471
 * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12472
 * <li>&lt;BandMetadataItem&gt; is the name of a band metadata item to use.</li>
12473
 * </ul>
12474
 * </li>
12475
 * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12476
 * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12477
 * Defaults to String.
12478
 * </li>
12479
 * <li>BAND_DIM_NAME=&lt;string&gt;: Name of the band dimension.
12480
 * Defaults to "Band".
12481
 * </li>
12482
 * <li>X_DIM_NAME=&lt;string&gt;: Name of the X dimension. Defaults to "X".
12483
 * </li>
12484
 * <li>Y_DIM_NAME=&lt;string&gt;: Name of the Y dimension. Defaults to "Y".
12485
 * </li>
12486
 * </ul>
12487
 *
12488
 * This is the same as the C function GDALDatasetAsMDArray().
12489
 *
12490
 * The "reverse" method is GDALMDArray::AsClassicDataset().
12491
 *
12492
 * @param papszOptions Null-terminated list of strings, or nullptr.
12493
 * @return a new array, or nullptr.
12494
 *
12495
 * @since GDAL 3.12
12496
 */
12497
std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12498
0
{
12499
0
    if (!GetShared())
12500
0
    {
12501
0
        MarkAsShared();
12502
0
    }
12503
0
    if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12504
0
    {
12505
0
        ReportError(
12506
0
            CE_Failure, CPLE_AppDefined,
12507
0
            "Degenerated array (band, Y and/or X dimension of size zero)");
12508
0
        return nullptr;
12509
0
    }
12510
0
    const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12511
0
    for (int i = 1; i < nBands; ++i)
12512
0
    {
12513
0
        if (eDT != papoBands[i]->GetRasterDataType())
12514
0
        {
12515
0
            ReportError(CE_Failure, CPLE_AppDefined,
12516
0
                        "Non-uniform data type amongst bands");
12517
0
            return nullptr;
12518
0
        }
12519
0
    }
12520
0
    const char *pszDimOrder =
12521
0
        CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12522
0
    if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12523
0
        !EQUAL(pszDimOrder, "Y,X,Band"))
12524
0
    {
12525
0
        ReportError(CE_Failure, CPLE_IllegalArg,
12526
0
                    "Illegal value for DIM_ORDER option");
12527
0
        return nullptr;
12528
0
    }
12529
0
    return GDALMDArrayFromDataset::Create(this, papszOptions);
12530
0
}
12531
12532
/************************************************************************/
12533
/*             GDALDataset::GetInterBandCovarianceMatrix()              */
12534
/************************************************************************/
12535
12536
/**
12537
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12538
12539
 The covariance indicates the level to which two bands vary together.
12540
12541
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12542
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12543
12544
 \f[
12545
    \mathrm{cov}[i,j] =
12546
    \frac{
12547
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12548
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12549
    }{
12550
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12551
    }
12552
 \f]
12553
12554
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12555
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12556
 is symmetric.
12557
12558
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12559
 if the pixels in bands are considered to be a sample of the whole population.
12560
 This is consistent with the default of
12561
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12562
 matrix is consistent with what can be obtained with
12563
12564
 \verbatim embed:rst
12565
 .. code-block:: python
12566
12567
     numpy.cov(
12568
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12569
     )
12570
 \endverbatim
12571
12572
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12573
 to be the whole population.
12574
12575
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12576
 this method uses them.
12577
 Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12578
 Otherwise, if bForce is false, an empty vector is returned
12579
12580
 @param nBandCount Zero for all bands, or number of values in panBandList.
12581
                   Defaults to 0.
12582
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12583
                    nBandCount values such as panBandList[i] is the index
12584
                    between 1 and GetRasterCount() of a band that must be used
12585
                    in the covariance computation. Defaults to nullptr.
12586
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12587
                  ComputeInterBandCovarianceMatrix().
12588
                  Defaults to false.
12589
 @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12590
               when the STATISTICS_COVARIANCES metadata items are missing.
12591
               Defaults to false.
12592
 @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12593
                           write STATISTICS_COVARIANCES band metadata items.
12594
                           Defaults to true.
12595
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12596
                              averaging phase of the covariance computation.
12597
                              Defaults to 1.
12598
 @param pfnProgress a function to call to report progress, or NULL.
12599
 @param pProgressData application data to pass to the progress function.
12600
12601
 @return a vector of nBandCount * nBandCount values if successful,
12602
         in row-major order, or an empty vector in case of failure
12603
12604
 @since 3.13
12605
12606
 @see ComputeInterBandCovarianceMatrix()
12607
 */
12608
12609
std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12610
    int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12611
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12612
    GDALProgressFunc pfnProgress, void *pProgressData)
12613
0
{
12614
0
    std::vector<double> res;
12615
0
    const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12616
0
    if (nBandCountToUse == 0)
12617
0
        return res;
12618
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
12619
    {
12620
        // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12621
        if (static_cast<uint32_t>(nBandCountToUse) >
12622
            std::numeric_limits<uint16_t>::max())
12623
        {
12624
            CPLError(CE_Failure, CPLE_OutOfMemory,
12625
                     "Not enough memory to store result");
12626
            return res;
12627
        }
12628
    }
12629
0
    try
12630
0
    {
12631
0
        res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12632
0
    }
12633
0
    catch (const std::exception &)
12634
0
    {
12635
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
12636
0
                 "Not enough memory to store result");
12637
0
        return res;
12638
0
    }
12639
12640
0
    if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12641
0
                                     panBandList, bApproxOK, bForce,
12642
0
                                     bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12643
0
                                     pfnProgress, pProgressData) != CE_None)
12644
0
    {
12645
0
        res.clear();
12646
0
    }
12647
0
    return res;
12648
0
}
12649
12650
/************************************************************************/
12651
/*             GDALDataset::GetInterBandCovarianceMatrix()              */
12652
/************************************************************************/
12653
12654
/**
12655
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12656
12657
 The covariance indicates the level to which two bands vary together.
12658
12659
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12660
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12661
12662
 \f[
12663
    \mathrm{cov}[i,j] =
12664
    \frac{
12665
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12666
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12667
    }{
12668
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12669
    }
12670
 \f]
12671
12672
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12673
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12674
 is symmetric.
12675
12676
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12677
 if the pixels in bands are considered to be a sample of the whole population.
12678
 This is consistent with the default of
12679
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12680
 matrix is consistent with what can be obtained with
12681
12682
 \verbatim embed:rst
12683
 .. code-block:: python
12684
12685
     numpy.cov(
12686
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12687
     )
12688
 \endverbatim
12689
12690
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12691
 to be the whole population.
12692
12693
 The caller must provide an already allocated array in padfCovMatrix of size
12694
 at least nBandCount * nBandCount.
12695
12696
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12697
 this method uses them.
12698
 Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12699
 Otherwise, if bForce is false, an empty vector is returned
12700
12701
 This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12702
12703
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12704
                      nBandCount * nBandCount.
12705
 @param nSize Number of elements in output array.
12706
 @param nBandCount Zero for all bands, or number of values in panBandList.
12707
                   Defaults to 0.
12708
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12709
                    nBandCount values such as panBandList[i] is the index
12710
                    between 1 and GetRasterCount() of a band that must be used
12711
                    in the covariance computation. Defaults to nullptr.
12712
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12713
                  ComputeInterBandCovarianceMatrix().
12714
                  Defaults to false.
12715
 @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12716
               when the STATISTICS_COVARIANCES metadata items are missing.
12717
               Defaults to false.
12718
 @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12719
                           write STATISTICS_COVARIANCES band metadata items.
12720
                           Defaults to true.
12721
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12722
                              averaging phase of the covariance computation.
12723
                              Defaults to 1.
12724
 @param pfnProgress a function to call to report progress, or NULL.
12725
 @param pProgressData application data to pass to the progress function.
12726
12727
 @return CE_None if successful, CE_Warning if values are not available in
12728
         metadata and bForce is false, or CE_Failure in case of failure
12729
12730
 @since 3.13
12731
12732
 @see ComputeInterBandCovarianceMatrix()
12733
 */
12734
12735
CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12736
    double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12737
    bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12738
    int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12739
    void *pProgressData)
12740
0
{
12741
0
    std::vector<int> anBandListTmp;  // keep in this scope
12742
0
    if (nBandCount == 0)
12743
0
    {
12744
0
        if (nBands == 0)
12745
0
            return CE_None;
12746
0
        for (int i = 0; i < nBands; ++i)
12747
0
            anBandListTmp.push_back(i + 1);
12748
0
        nBandCount = nBands;
12749
0
        panBandList = anBandListTmp.data();
12750
0
    }
12751
0
    else
12752
0
    {
12753
0
        if (nBandCount > nBands)
12754
0
        {
12755
0
            CPLError(CE_Failure, CPLE_AppDefined,
12756
0
                     "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12757
0
            return CE_Failure;
12758
0
        }
12759
0
        for (int i = 0; i < nBandCount; ++i)
12760
0
        {
12761
0
            if (panBandList[i] <= 0 || panBandList[i] > nBands)
12762
0
            {
12763
0
                CPLError(CE_Failure, CPLE_AppDefined,
12764
0
                         "GetInterBandCovarianceMatrix(): invalid value "
12765
0
                         "panBandList[%d] = %d",
12766
0
                         i, panBandList[i]);
12767
0
                return CE_Failure;
12768
0
            }
12769
0
        }
12770
0
    }
12771
12772
0
    if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12773
0
    {
12774
0
        CPLError(
12775
0
            CE_Failure, CPLE_AppDefined,
12776
0
            "GetInterBandCovarianceMatrix(): too small result matrix provided");
12777
0
        return CE_Failure;
12778
0
    }
12779
0
    bool bGotFromMD = true;
12780
0
    size_t resIdx = 0;
12781
0
    for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12782
0
    {
12783
0
        const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12784
0
            "STATISTICS_COVARIANCES");
12785
0
        bGotFromMD = pszCov != nullptr;
12786
0
        if (bGotFromMD)
12787
0
        {
12788
0
            const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12789
0
            bGotFromMD = aosTokens.size() == nBands;
12790
0
            if (bGotFromMD)
12791
0
            {
12792
0
                for (int j = 0; j < nBandCount; ++j)
12793
0
                    padfCovMatrix[resIdx++] =
12794
0
                        CPLAtof(aosTokens[panBandList[j] - 1]);
12795
0
            }
12796
0
        }
12797
0
    }
12798
0
    if (bGotFromMD)
12799
0
        return CE_None;
12800
12801
0
    if (!bForce)
12802
0
        return CE_Warning;
12803
0
    return ComputeInterBandCovarianceMatrix(
12804
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12805
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12806
0
}
12807
12808
/************************************************************************/
12809
/*              GDALDatasetGetInterBandCovarianceMatrix()               */
12810
/************************************************************************/
12811
12812
/**
12813
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12814
12815
 The covariance indicates the level to which two bands vary together.
12816
12817
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12818
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12819
12820
 \f[
12821
    \mathrm{cov}[i,j] =
12822
    \frac{
12823
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12824
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12825
    }{
12826
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12827
    }
12828
 \f]
12829
12830
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12831
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12832
 is symmetric.
12833
12834
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12835
 if the pixels in bands are considered to be a sample of the whole population.
12836
 This is consistent with the default of
12837
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12838
 matrix is consistent with what can be obtained with
12839
12840
 \verbatim embed:rst
12841
 .. code-block:: python
12842
12843
     numpy.cov(
12844
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12845
     )
12846
 \endverbatim
12847
12848
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12849
 to be the whole population.
12850
12851
 The caller must provide an already allocated array in padfCovMatrix of size
12852
 at least nBandCount * nBandCount.
12853
12854
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12855
 this method uses them.
12856
 Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12857
 Otherwise, if bForce is false, an empty vector is returned
12858
12859
 This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12860
12861
 @param hDS Dataset handle.
12862
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12863
                      nBandCount * nBandCount.
12864
 @param nSize Number of elements in output array.
12865
 @param nBandCount Zero for all bands, or number of values in panBandList.
12866
                   Defaults to 0.
12867
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12868
                    nBandCount values such as panBandList[i] is the index
12869
                    between 1 and GetRasterCount() of a band that must be used
12870
                    in the covariance computation. Defaults to nullptr.
12871
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12872
                  GDALDatasetComputeInterBandCovarianceMatrix().
12873
                  Defaults to false.
12874
 @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12875
               when the STATISTICS_COVARIANCES metadata items are missing.
12876
               Defaults to false.
12877
 @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12878
                           write STATISTICS_COVARIANCES band metadata items.
12879
                           Defaults to true.
12880
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12881
                              averaging phase of the covariance computation.
12882
                              Defaults to 1.
12883
 @param pfnProgress a function to call to report progress, or NULL.
12884
 @param pProgressData application data to pass to the progress function.
12885
12886
 @return CE_None if successful, CE_Warning if values are not available in
12887
         metadata and bForce is false, or CE_Failure in case of failure
12888
12889
 @since 3.13
12890
12891
 @see GDALDatasetComputeInterBandCovarianceMatrix()
12892
 */
12893
CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12894
    GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12895
    const int *panBandList, bool bApproxOK, bool bForce,
12896
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12897
    GDALProgressFunc pfnProgress, void *pProgressData)
12898
0
{
12899
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12900
0
    VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12901
0
    return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12902
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12903
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12904
0
}
12905
12906
/************************************************************************/
12907
/*           GDALDataset::ComputeInterBandCovarianceMatrix()            */
12908
/************************************************************************/
12909
12910
/**
12911
 \brief Compute the covariance matrix between bands of this dataset.
12912
12913
 The covariance indicates the level to which two bands vary together.
12914
12915
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12916
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12917
12918
 \f[
12919
    \mathrm{cov}[i,j] =
12920
    \frac{
12921
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12922
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12923
    }{
12924
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12925
    }
12926
 \f]
12927
12928
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12929
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12930
 is symmetric.
12931
12932
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12933
 if the pixels in bands are considered to be a sample of the whole population.
12934
 This is consistent with the default of
12935
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12936
 matrix is consistent with what can be obtained with
12937
12938
 \verbatim embed:rst
12939
 .. code-block:: python
12940
12941
     numpy.cov(
12942
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12943
     )
12944
 \endverbatim
12945
12946
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12947
 to be the whole population.
12948
12949
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12950
 metadata items are available in bands. See GetInterBandCovarianceMatrix()
12951
 to use them.
12952
12953
 @param nBandCount Zero for all bands, or number of values in panBandList.
12954
                   Defaults to 0.
12955
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12956
                    nBandCount values such as panBandList[i] is the index
12957
                    between 1 and GetRasterCount() of a band that must be used
12958
                    in the covariance computation. Defaults to nullptr.
12959
 @param bApproxOK Whether it is acceptable to use a subsample of values.
12960
                  Defaults to false.
12961
 @param bWriteIntoMetadata Whether this method must write
12962
                           STATISTICS_COVARIANCES band metadata items.
12963
                           Defaults to true.
12964
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12965
                              averaging phase of the covariance computation.
12966
                              Defaults to 1.
12967
 @param pfnProgress a function to call to report progress, or NULL.
12968
 @param pProgressData application data to pass to the progress function.
12969
12970
 @return a vector of nBandCount * nBandCount values if successful,
12971
         in row-major order, or an empty vector in case of failure
12972
12973
 @since 3.13
12974
12975
 @see GetInterBandCovarianceMatrix()
12976
 */
12977
std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12978
    int nBandCount, const int *panBandList, bool bApproxOK,
12979
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12980
    GDALProgressFunc pfnProgress, void *pProgressData)
12981
0
{
12982
0
    std::vector<double> res;
12983
0
    const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12984
0
    if (nBandCountToUse == 0)
12985
0
        return res;
12986
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
12987
    {
12988
        // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12989
        if (static_cast<uint32_t>(nBandCountToUse) >
12990
            std::numeric_limits<uint16_t>::max())
12991
        {
12992
            CPLError(CE_Failure, CPLE_OutOfMemory,
12993
                     "Not enough memory to store result");
12994
            return res;
12995
        }
12996
    }
12997
0
    try
12998
0
    {
12999
0
        res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
13000
0
    }
13001
0
    catch (const std::exception &)
13002
0
    {
13003
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
13004
0
                 "Not enough memory to store result");
13005
0
        return res;
13006
0
    }
13007
13008
0
    if (ComputeInterBandCovarianceMatrix(
13009
0
            res.data(), res.size(), nBandCount, panBandList, bApproxOK,
13010
0
            bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
13011
0
            pProgressData) != CE_None)
13012
0
        res.clear();
13013
0
    return res;
13014
0
}
13015
13016
/************************************************************************/
13017
/*              ComputeInterBandCovarianceMatrixInternal()              */
13018
/************************************************************************/
13019
13020
template <class T>
13021
// CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
13022
// causes that to happen
13023
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
13024
ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
13025
                                         double *padfCovMatrix, int nBandCount,
13026
                                         const int *panBandList,
13027
                                         GDALRasterBand *const *papoBands,
13028
                                         int nDeltaDegreeOfFreedom,
13029
                                         GDALProgressFunc pfnProgress,
13030
                                         void *pProgressData)
13031
0
{
13032
    // We use the padfCovMatrix to accumulate co-moments
13033
    // Dimension = nBandCount * nBandCount
13034
0
    double *const padfComomentMatrix = padfCovMatrix;
13035
13036
    // Matrix of  nBandCount * nBandCount storing co-moments, in optimized
13037
    // case when the block has no nodata value
13038
    // Only used if T != double
13039
0
    [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
13040
13041
    // Count number of valid values in padfComomentMatrix for each (i,j) tuple
13042
    // Updated while iterating over blocks
13043
    // Dimension = nBandCount * nBandCount
13044
0
    std::vector<uint64_t> anCount;
13045
13046
    // Mean of bands, for each (i,j) tuple.
13047
    // Updated while iterating over blocks.
13048
    // This is a matrix rather than a vector due to the fact when need to update
13049
    // it in sync with padfComomentMatrix
13050
    // Dimension = nBandCount * nBandCount
13051
0
    std::vector<T> adfMean;
13052
13053
    // Number of valid values when computing adfMean, for each (i,j) tuple.
13054
    // Updated while iterating over blocks.
13055
    // This is a matrix rather than a vector due to the fact when need to update
13056
    // it in sync with padfComomentMatrix
13057
    // Dimension = nBandCount * nBandCount
13058
0
    std::vector<uint64_t> anCountMean;
13059
13060
    // Mean of values for each band i. Refreshed for each block.
13061
    // Dimension = nBandCount
13062
0
    std::vector<T> adfCurBlockMean;
13063
13064
    // Number of values participating to the mean for each band i.
13065
    // Refreshed for each block. Dimension = nBandCount
13066
0
    std::vector<size_t> anCurBlockCount;
13067
13068
    // Pixel values for all selected values for the current block
13069
    // Dimension = nBlockXSize * nBlockYSize * nBandCount
13070
0
    std::vector<T> adfCurBlockPixelsAllBands;
13071
13072
    // Vector of nodata values for all bands. Dimension = nBandCount
13073
0
    std::vector<T> adfNoData;
13074
13075
    // Vector of mask bands for all bands. Dimension = nBandCount
13076
0
    std::vector<GDALRasterBand *> apoMaskBands;
13077
13078
    // Vector of vector of mask values. Dimension = nBandCount
13079
0
    std::vector<std::vector<GByte>> aabyCurBlockMask;
13080
13081
    // Vector of pointer to vector of mask values. Dimension = nBandCount
13082
0
    std::vector<std::vector<GByte> *> pabyCurBlockMask;
13083
13084
0
    int nBlockXSize = 0;
13085
0
    int nBlockYSize = 0;
13086
0
    papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
13087
13088
0
    if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
13089
0
        std::numeric_limits<size_t>::max() / nBandCount)
13090
0
    {
13091
0
        poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13092
0
                          "Not enough memory for intermediate computations");
13093
0
        return CE_Failure;
13094
0
    }
13095
0
    const size_t nPixelsInBlock =
13096
0
        static_cast<size_t>(nBlockXSize) * nBlockYSize;
13097
13098
    // Allocate temporary matrices and vectors
13099
0
    const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13100
13101
0
    using MySignedSize_t = std::make_signed_t<size_t>;
13102
0
    const auto kMax =
13103
0
        static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
13104
0
    std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
13105
0
    try
13106
0
    {
13107
0
        anCount.resize(nMatrixSize);
13108
0
        adfMean.resize(nMatrixSize);
13109
0
        anCountMean.resize(nMatrixSize);
13110
13111
        if constexpr (!std::is_same_v<T, double>)
13112
        {
13113
            aCurBlockComomentMatrix.resize(nMatrixSize);
13114
        }
13115
13116
0
        anMapLinearIdxToIJ.resize(kMax);
13117
13118
0
        adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13119
13120
0
        adfCurBlockMean.resize(nBandCount);
13121
0
        anCurBlockCount.resize(nBandCount);
13122
0
        adfNoData.resize(nBandCount);
13123
0
        apoMaskBands.resize(nBandCount);
13124
0
        aabyCurBlockMask.resize(nBandCount);
13125
0
        pabyCurBlockMask.resize(nBandCount);
13126
0
    }
13127
0
    catch (const std::exception &)
13128
0
    {
13129
0
        poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13130
0
                          "Not enough memory for intermediate computations");
13131
0
        return CE_Failure;
13132
0
    }
13133
13134
0
    constexpr T ZERO{0};
13135
0
    std::fill(padfComomentMatrix,
13136
0
              padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13137
0
              0);
13138
13139
0
    {
13140
0
        MySignedSize_t nLinearIdx = 0;
13141
0
        for (int i = 0; i < nBandCount; ++i)
13142
0
        {
13143
0
            for (int j = i; j < nBandCount; ++j)
13144
0
            {
13145
0
                anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13146
0
                ++nLinearIdx;
13147
0
            }
13148
0
        }
13149
0
    }
13150
13151
    // Fetch nodata values and mask bands
13152
0
    bool bAllBandsSameMask = false;
13153
0
    bool bIsAllInteger = false;
13154
0
    bool bNoneHasMaskOrNodata = false;
13155
0
    for (int i = 0; i < nBandCount; ++i)
13156
0
    {
13157
0
        const auto poBand = papoBands[panBandList[i] - 1];
13158
0
        bIsAllInteger = (i == 0 || bIsAllInteger) &&
13159
0
                        GDALDataTypeIsInteger(poBand->GetRasterDataType());
13160
0
        int bHasNoData = FALSE;
13161
0
        double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13162
0
        if (!bHasNoData)
13163
0
        {
13164
0
            dfNoData = std::numeric_limits<double>::quiet_NaN();
13165
13166
0
            if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13167
0
                poBand->GetColorInterpretation() != GCI_AlphaBand)
13168
0
            {
13169
0
                apoMaskBands[i] = poBand->GetMaskBand();
13170
0
                try
13171
0
                {
13172
0
                    aabyCurBlockMask[i].resize(nPixelsInBlock);
13173
0
                }
13174
0
                catch (const std::exception &)
13175
0
                {
13176
0
                    poDS->ReportError(
13177
0
                        CE_Failure, CPLE_OutOfMemory,
13178
0
                        "Not enough memory for intermediate computations");
13179
0
                    return CE_Failure;
13180
0
                }
13181
0
#ifndef __COVERITY__
13182
                // coverity[escape]
13183
0
                pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13184
0
#endif
13185
0
            }
13186
0
        }
13187
0
        adfNoData[i] = static_cast<T>(dfNoData);
13188
0
        if (i == 0)
13189
0
            bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13190
0
        else if (bAllBandsSameMask)
13191
0
            bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13192
13193
0
        bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13194
0
                               std::isnan(dfNoData) &&
13195
0
                               apoMaskBands[i] == nullptr;
13196
0
    }
13197
0
    if (bAllBandsSameMask)
13198
0
    {
13199
0
        for (int i = 1; i < nBandCount; ++i)
13200
0
        {
13201
0
            apoMaskBands[i] = nullptr;
13202
0
            aabyCurBlockMask[i].clear();
13203
0
            pabyCurBlockMask[i] = pabyCurBlockMask[0];
13204
0
        }
13205
0
    }
13206
13207
0
    const auto nIterCount =
13208
0
        static_cast<uint64_t>(
13209
0
            cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13210
0
        cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13211
0
    uint64_t nCurIter = 0;
13212
13213
0
    int nNumThreads = 1;
13214
#ifdef HAVE_OPENMP
13215
    if (nBandCount >= 100)
13216
    {
13217
        const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13218
        nNumThreads =
13219
            GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13220
    }
13221
#endif
13222
13223
0
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13224
0
    const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13225
0
                              __builtin_cpu_supports("avx2") &&
13226
0
                              __builtin_cpu_supports("fma");
13227
0
#endif
13228
13229
    // Iterate over all blocks
13230
0
    for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13231
0
    {
13232
0
        const auto nThisBlockPixelCount =
13233
0
            static_cast<size_t>(window.nXSize) * window.nYSize;
13234
13235
        // Extract pixel values and masks
13236
0
        CPLErr eErr = poDS->RasterIO(
13237
0
            GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13238
0
            adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13239
0
            gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13240
0
            nullptr);
13241
0
        if (eErr == CE_None && bAllBandsSameMask)
13242
0
        {
13243
0
            eErr = apoMaskBands[0]->RasterIO(
13244
0
                GF_Read, window.nXOff, window.nYOff, window.nXSize,
13245
0
                window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13246
0
                window.nYSize, GDT_Byte, 0, 0, nullptr);
13247
0
        }
13248
0
        else
13249
0
        {
13250
0
            for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13251
0
            {
13252
0
                if (apoMaskBands[i])
13253
0
                {
13254
0
                    eErr = apoMaskBands[i]->RasterIO(
13255
0
                        GF_Read, window.nXOff, window.nYOff, window.nXSize,
13256
0
                        window.nYSize, aabyCurBlockMask[i].data(),
13257
0
                        window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13258
0
                }
13259
0
            }
13260
0
        }
13261
0
        if (eErr != CE_None)
13262
0
            return eErr;
13263
13264
        // Compute the mean of all bands for this block
13265
0
        bool bAllBandsAreAllNodata = false;
13266
0
        bool bNoBandHasNodata = false;
13267
0
        for (int i = 0; i < nBandCount; ++i)
13268
0
        {
13269
0
            T dfSum = 0;
13270
0
            size_t nCount = 0;
13271
0
            const T dfNoDataI = adfNoData[i];
13272
0
            const T *padfI =
13273
0
                adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13274
0
#ifdef HAVE_OPENMP_SIMD
13275
0
#pragma omp simd reduction(+ : dfSum)
13276
0
#endif
13277
0
            for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13278
0
            {
13279
0
                const T dfI = padfI[iPixel];
13280
0
                const bool bIsValid =
13281
0
                    !std::isnan(dfI) && dfI != dfNoDataI &&
13282
0
                    (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13283
0
                nCount += bIsValid;
13284
0
                dfSum += bIsValid ? dfI : ZERO;
13285
0
            }
13286
0
            adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13287
0
            anCurBlockCount[i] = nCount;
13288
0
            bAllBandsAreAllNodata =
13289
0
                (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13290
0
            bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13291
0
                               (nCount == nThisBlockPixelCount);
13292
0
        }
13293
13294
        // Modify the pixel values to shift them by minus the mean
13295
0
        if (!bAllBandsAreAllNodata)
13296
0
        {
13297
0
            for (int i = 0; i < nBandCount; ++i)
13298
0
            {
13299
0
                T *padfI =
13300
0
                    adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13301
0
                const T dfMeanI = adfCurBlockMean[i];
13302
0
                for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13303
0
                {
13304
0
                    padfI[iPixel] -= dfMeanI;
13305
0
                }
13306
0
            }
13307
0
        }
13308
13309
        // Update padfComomentMatrix, anCount, adfMean, anCountMean
13310
        // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13311
0
        const auto UpdateGlobalValues =
13312
0
            [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13313
0
             &anCurBlockCount, padfComomentMatrix,
13314
0
             nBandCount](int i, int j, size_t nCount, T dfComoment)
13315
0
        {
13316
0
            const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13317
0
            const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13318
13319
            // Update the total comoment using last formula of paragraph
13320
            // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13321
            // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13322
            //                 (mean_I(A) - mean_I(B)) *
13323
            //                 (mean_J(A) - mean_J(B)) *
13324
            //                 (count(A) * count(B)) / (count(A) + count(B))
13325
            //
13326
            // There might be a small gotcha in the fact that the set of
13327
            // pixels on which the means are computed is not always the
13328
            // same as the the one on which the comoment is computed, if
13329
            // pixels are not valid/invalid at the same indices among bands
13330
            // It is not obvious (to me) what should be the correct behavior.
13331
            // The current approach has the benefit to avoid recomputing
13332
            // the mean for each (i,j) tuple, but only for all i.
13333
0
            if (nCount > 0)
13334
0
            {
13335
0
                padfComomentMatrix[idxInMatrixI] +=
13336
0
                    static_cast<double>(dfComoment);
13337
0
                padfComomentMatrix[idxInMatrixI] +=
13338
0
                    static_cast<double>(adfMean[idxInMatrixI] -
13339
0
                                        adfCurBlockMean[i]) *
13340
0
                    static_cast<double>(adfMean[idxInMatrixJ] -
13341
0
                                        adfCurBlockMean[j]) *
13342
0
                    (static_cast<double>(anCount[idxInMatrixI]) *
13343
0
                     static_cast<double>(nCount) /
13344
0
                     static_cast<double>(anCount[idxInMatrixI] + nCount));
13345
13346
0
                anCount[idxInMatrixI] += nCount;
13347
0
            }
13348
13349
            // Update means
13350
0
            if (anCurBlockCount[i] > 0)
13351
0
            {
13352
0
                adfMean[idxInMatrixI] +=
13353
0
                    (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13354
0
                    static_cast<T>(
13355
0
                        static_cast<double>(anCurBlockCount[i]) /
13356
0
                        static_cast<double>(anCountMean[idxInMatrixI] +
13357
0
                                            anCurBlockCount[i]));
13358
13359
0
                anCountMean[idxInMatrixI] += anCurBlockCount[i];
13360
0
            }
13361
13362
0
            if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13363
0
            {
13364
0
                adfMean[idxInMatrixJ] +=
13365
0
                    (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13366
0
                    static_cast<T>(
13367
0
                        static_cast<double>(anCurBlockCount[j]) /
13368
0
                        static_cast<double>(anCountMean[idxInMatrixJ] +
13369
0
                                            anCurBlockCount[j]));
13370
13371
0
                anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13372
0
            }
13373
0
        };
13374
13375
0
        if (bAllBandsAreAllNodata)
13376
0
        {
13377
            // Optimized code path where all values in the current block
13378
            // are invalid
13379
13380
0
            for (int i = 0; i < nBandCount; ++i)
13381
0
            {
13382
0
                for (int j = i; j < nBandCount; ++j)
13383
0
                {
13384
0
                    UpdateGlobalValues(i, j, 0, ZERO);
13385
0
                }
13386
0
            }
13387
0
        }
13388
0
        else if (bNoBandHasNodata)
13389
0
        {
13390
            // Optimized code path where there are no invalid value in the
13391
            // current block
13392
13393
            if constexpr (!std::is_same_v<T, double>)
13394
            {
13395
                std::fill(aCurBlockComomentMatrix.begin(),
13396
                          aCurBlockComomentMatrix.end(), ZERO);
13397
13398
                GDALMatrixMultiplyAByTransposeAUpperTriangle(
13399
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13400
                    aCurBlockComomentMatrix.data(), nBandCount,
13401
                    nThisBlockPixelCount);
13402
            }
13403
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13404
0
            else if (bHasAVX2_FMA)
13405
0
            {
13406
0
                GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13407
0
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13408
0
                    padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13409
0
            }
13410
0
#endif
13411
0
            else
13412
0
            {
13413
0
                GDALMatrixMultiplyAByTransposeAUpperTriangle(
13414
0
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13415
0
                    padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13416
0
            }
13417
13418
0
            for (int i = 0; i < nBandCount; ++i)
13419
0
            {
13420
0
                for (int j = i; j < nBandCount; ++j)
13421
0
                {
13422
                    if constexpr (!std::is_same_v<T, double>)
13423
                    {
13424
                        const auto idxInMatrixI =
13425
                            static_cast<size_t>(i) * nBandCount + j;
13426
                        UpdateGlobalValues(
13427
                            i, j, nThisBlockPixelCount,
13428
                            aCurBlockComomentMatrix[idxInMatrixI]);
13429
                    }
13430
                    else
13431
0
                    {
13432
0
                        UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13433
0
                    }
13434
0
                }
13435
0
            }
13436
0
        }
13437
0
        else
13438
0
        {
13439
#ifdef HAVE_OPENMP
13440
#pragma omp parallel for schedule(static) num_threads(nNumThreads)
13441
#endif
13442
0
            for (MySignedSize_t k = 0; k < kMax; ++k)
13443
0
            {
13444
0
                int i, j;
13445
0
                std::tie(i, j) = anMapLinearIdxToIJ[k];
13446
13447
                // Now compute the moment of (i, j), but just for this block
13448
0
                size_t nCount = 0;
13449
0
                T dfComoment = 0;
13450
0
                const T *padfI =
13451
0
                    adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13452
0
                const T *padfJ =
13453
0
                    adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13454
13455
                // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13456
                // for the current block
13457
0
                if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13458
0
                     anCurBlockCount[j] == nThisBlockPixelCount) ||
13459
0
                    (bNoneHasMaskOrNodata && bIsAllInteger))
13460
0
                {
13461
                    // Most optimized code path: integer, no nodata, no mask
13462
0
#ifdef HAVE_OPENMP_SIMD
13463
0
#pragma omp simd reduction(+ : dfComoment)
13464
0
#endif
13465
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13466
0
                         ++iPixel)
13467
0
                    {
13468
0
                        dfComoment += padfI[iPixel] * padfJ[iPixel];
13469
0
                    }
13470
0
                    nCount = nThisBlockPixelCount;
13471
0
                }
13472
0
                else if (bNoneHasMaskOrNodata)
13473
0
                {
13474
                    // Floating-point code path with no nodata and no mask
13475
0
#ifdef HAVE_OPENMP_SIMD
13476
0
#pragma omp simd reduction(+ : dfComoment)
13477
0
#endif
13478
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13479
0
                         ++iPixel)
13480
0
                    {
13481
0
                        const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13482
0
                        const bool bIsValid = !std::isnan(dfAcc);
13483
0
                        nCount += bIsValid;
13484
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13485
0
                    }
13486
0
                }
13487
0
                else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13488
0
                {
13489
                    // Code path when there are both nodata values
13490
0
                    const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13491
0
                    const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13492
13493
0
#ifdef HAVE_OPENMP_SIMD
13494
0
#pragma omp simd reduction(+ : dfComoment)
13495
0
#endif
13496
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13497
0
                         ++iPixel)
13498
0
                    {
13499
0
                        const T dfI = padfI[iPixel];
13500
0
                        const T dfJ = padfJ[iPixel];
13501
0
                        const T dfAcc = dfI * dfJ;
13502
0
                        const bool bIsValid = !std::isnan(dfAcc) &&
13503
0
                                              dfI != shiftedNoDataI &&
13504
0
                                              dfJ != shiftedNoDataJ;
13505
0
                        nCount += bIsValid;
13506
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13507
0
                    }
13508
0
                }
13509
0
                else
13510
0
                {
13511
                    // Generic code path
13512
0
                    const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13513
0
                    const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13514
13515
0
#ifdef HAVE_OPENMP_SIMD
13516
0
#pragma omp simd reduction(+ : dfComoment)
13517
0
#endif
13518
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13519
0
                         ++iPixel)
13520
0
                    {
13521
0
                        const T dfI = padfI[iPixel];
13522
0
                        const T dfJ = padfJ[iPixel];
13523
0
                        const T dfAcc = dfI * dfJ;
13524
0
                        const bool bIsValid =
13525
0
                            !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13526
0
                            dfJ != shiftedNoDataJ &&
13527
0
                            (!pabyCurBlockMask[i] ||
13528
0
                             (*pabyCurBlockMask[i])[iPixel]) &&
13529
0
                            (!pabyCurBlockMask[j] ||
13530
0
                             (*pabyCurBlockMask[j])[iPixel]);
13531
0
                        nCount += bIsValid;
13532
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13533
0
                    }
13534
0
                }
13535
13536
0
                UpdateGlobalValues(i, j, nCount, dfComoment);
13537
0
            }
13538
0
        }
13539
13540
0
        ++nCurIter;
13541
0
        if (pfnProgress &&
13542
0
            !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13543
0
                         pProgressData))
13544
0
        {
13545
0
            poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13546
0
                              "User terminated");
13547
0
            return CE_Failure;
13548
0
        }
13549
0
    }
13550
13551
    // Finalize by dividing co-moments by the number of contributing values
13552
    // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13553
0
    for (int i = 0; i < nBandCount; ++i)
13554
0
    {
13555
        // The covariance matrix is symmetric. So start at i
13556
0
        for (int j = i; j < nBandCount; ++j)
13557
0
        {
13558
0
            const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13559
0
            const double dfCovariance =
13560
0
                (nDeltaDegreeOfFreedom < 0 ||
13561
0
                 anCount[idxInMatrixI] <=
13562
0
                     static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13563
0
                    ? std::numeric_limits<double>::quiet_NaN()
13564
0
                    : padfComomentMatrix[idxInMatrixI] /
13565
0
                          static_cast<double>(anCount[idxInMatrixI] -
13566
0
                                              nDeltaDegreeOfFreedom);
13567
13568
0
            padfCovMatrix[idxInMatrixI] = dfCovariance;
13569
            // Fill lower triangle
13570
0
            padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13571
0
                dfCovariance;
13572
0
        }
13573
0
    }
13574
13575
0
    return CE_None;
13576
0
}
13577
13578
/************************************************************************/
13579
/*           GDALDataset::ComputeInterBandCovarianceMatrix()            */
13580
/************************************************************************/
13581
13582
/**
13583
 \brief Compute the covariance matrix between bands of this dataset.
13584
13585
 The covariance indicates the level to which two bands vary together.
13586
13587
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13588
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
13589
13590
 \f[
13591
    \mathrm{cov}[i,j] =
13592
    \frac{
13593
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13594
        \left( v_j[y,x] - \mathrm{mean}_j \right)
13595
    }{
13596
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13597
    }
13598
 \f]
13599
13600
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13601
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13602
 is symmetric.
13603
13604
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13605
 if the pixels in bands are considered to be a sample of the whole population.
13606
 This is consistent with the default of
13607
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13608
 matrix is consistent with what can be obtained with
13609
13610
 \verbatim embed:rst
13611
 .. code-block:: python
13612
13613
     numpy.cov(
13614
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13615
     )
13616
 \endverbatim
13617
13618
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13619
 to be the whole population.
13620
13621
 The caller must provide an already allocated array in padfCovMatrix of size
13622
 at least nBandCount * nBandCount.
13623
13624
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13625
 metadata items are available in bands. See GetInterBandCovarianceMatrix()
13626
 to use them.
13627
13628
 The implementation is optimized to minimize the amount of pixel reading.
13629
13630
 This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13631
13632
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13633
                      nBandCount * nBandCount.
13634
 @param nSize Number of elements in output array.
13635
 @param nBandCount Zero for all bands, or number of values in panBandList.
13636
                   Defaults to 0.
13637
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
13638
                    nBandCount values such as panBandList[i] is the index
13639
                    between 1 and GetRasterCount() of a band that must be used
13640
                    in the covariance computation. Defaults to nullptr.
13641
 @param bApproxOK Whether it is acceptable to use a subsample of values.
13642
                  Defaults to false.
13643
 @param bWriteIntoMetadata Whether this method must write
13644
                           STATISTICS_COVARIANCES band metadata items.
13645
                           Defaults to true.
13646
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13647
                              averaging phase of the covariance computation.
13648
                              Defaults to 1.
13649
 @param pfnProgress a function to call to report progress, or NULL.
13650
 @param pProgressData application data to pass to the progress function.
13651
13652
 @return CE_None if successful, or CE_Failure in case of failure
13653
13654
 @since 3.13
13655
13656
 @see GetInterBandCovarianceMatrix()
13657
 */
13658
CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13659
    double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13660
    bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13661
    GDALProgressFunc pfnProgress, void *pProgressData)
13662
0
{
13663
0
    std::vector<int> anBandListTmp;  // keep in this scope
13664
0
    if (nBandCount == 0)
13665
0
    {
13666
0
        if (nBands == 0)
13667
0
            return CE_None;
13668
0
        for (int i = 0; i < nBands; ++i)
13669
0
            anBandListTmp.push_back(i + 1);
13670
0
        nBandCount = nBands;
13671
0
        panBandList = anBandListTmp.data();
13672
0
    }
13673
0
    else
13674
0
    {
13675
0
        if (nBandCount > nBands)
13676
0
        {
13677
0
            CPLError(CE_Failure, CPLE_AppDefined,
13678
0
                     "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13679
0
            return CE_Failure;
13680
0
        }
13681
0
        for (int i = 0; i < nBandCount; ++i)
13682
0
        {
13683
0
            if (panBandList[i] <= 0 || panBandList[i] > nBands)
13684
0
            {
13685
0
                CPLError(CE_Failure, CPLE_AppDefined,
13686
0
                         "ComputeInterBandCovarianceMatrix(): invalid value "
13687
0
                         "panBandList[%d] = %d",
13688
0
                         i, panBandList[i]);
13689
0
                return CE_Failure;
13690
0
            }
13691
0
        }
13692
13693
0
        if (bWriteIntoMetadata)
13694
0
        {
13695
0
            bool bOK = nBandCount == nBands;
13696
0
            for (int i = 0; bOK && i < nBandCount; ++i)
13697
0
            {
13698
0
                bOK = (panBandList[i] == i + 1);
13699
0
            }
13700
0
            if (!bOK)
13701
0
            {
13702
0
                CPLError(CE_Failure, CPLE_AppDefined,
13703
0
                         "ComputeInterBandCovarianceMatrix(): cannot write "
13704
0
                         "STATISTICS_COVARIANCES metadata since the input band "
13705
0
                         "list is not [1, 2, ... GetRasterCount()]");
13706
0
                return CE_Failure;
13707
0
            }
13708
0
        }
13709
0
    }
13710
13711
0
    const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13712
0
    if (nSize < nMatrixSize)
13713
0
    {
13714
0
        CPLError(CE_Failure, CPLE_AppDefined,
13715
0
                 "ComputeInterBandCovarianceMatrix(): too small result matrix "
13716
0
                 "provided");
13717
0
        return CE_Failure;
13718
0
    }
13719
13720
    // Find appropriate overview dataset
13721
0
    GDALDataset *poActiveDS = this;
13722
0
    if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13723
0
    {
13724
0
        GDALDataset *poOvrDS = nullptr;
13725
0
        for (int i = 0; i < nBandCount; ++i)
13726
0
        {
13727
0
            const int nIdxBand = panBandList[i] - 1;
13728
0
            auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13729
0
                GDALSTAT_APPROX_NUMSAMPLES);
13730
13731
0
            if (poOvrBand == papoBands[i] ||
13732
0
                poOvrBand->GetBand() != panBandList[i])
13733
0
            {
13734
0
                poOvrDS = nullptr;
13735
0
                break;
13736
0
            }
13737
0
            else if (i == 0)
13738
0
            {
13739
0
                if (poOvrBand->GetDataset() == this)
13740
0
                {
13741
0
                    break;
13742
0
                }
13743
0
                poOvrDS = poOvrBand->GetDataset();
13744
0
            }
13745
0
            else if (poOvrBand->GetDataset() != poOvrDS)
13746
0
            {
13747
0
                poOvrDS = nullptr;
13748
0
                break;
13749
0
            }
13750
0
        }
13751
0
        if (poOvrDS)
13752
0
        {
13753
0
            poActiveDS = poOvrDS;
13754
0
        }
13755
0
    }
13756
13757
#ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13758
    const auto UseFloat32 = [](GDALDataType eDT)
13759
    {
13760
        return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13761
               eDT == GDT_Int16 || eDT == GDT_Float32;
13762
    };
13763
13764
    bool bUseFloat32 = UseFloat32(
13765
        poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13766
    for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13767
    {
13768
        bUseFloat32 = UseFloat32(
13769
            poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13770
    }
13771
#endif
13772
13773
0
    CPLErr eErr =
13774
#ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13775
        bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13776
                          poActiveDS, padfCovMatrix, nBandCount, panBandList,
13777
                          poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13778
                          pfnProgress, pProgressData)
13779
                    :
13780
#endif
13781
0
                    ComputeInterBandCovarianceMatrixInternal<double>(
13782
0
                        poActiveDS, padfCovMatrix, nBandCount, panBandList,
13783
0
                        poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13784
0
                        pfnProgress, pProgressData);
13785
13786
0
    if (bWriteIntoMetadata && eErr == CE_None)
13787
0
    {
13788
0
        CPLAssert(nBands == nBandCount);
13789
0
        std::string osStr;
13790
0
        size_t idx = 0;
13791
0
        for (int i = 0; i < nBands; ++i)
13792
0
        {
13793
0
            osStr.clear();
13794
0
            for (int j = 0; j < nBands; ++j, ++idx)
13795
0
            {
13796
0
                if (j > 0)
13797
0
                    osStr += ',';
13798
0
                osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13799
0
            }
13800
0
            papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13801
0
                                          osStr.c_str());
13802
0
        }
13803
0
    }
13804
13805
0
    return eErr;
13806
0
}
13807
13808
/************************************************************************/
13809
/*            GDALDatasetComputeInterBandCovarianceMatrix()             */
13810
/************************************************************************/
13811
13812
/**
13813
 \brief Compute the covariance matrix between bands of this dataset.
13814
13815
 The covariance indicates the level to which two bands vary together.
13816
13817
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13818
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
13819
13820
 \f[
13821
    \mathrm{cov}[i,j] =
13822
    \frac{
13823
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13824
        \left( v_j[y,x] - \mathrm{mean}_j \right)
13825
    }{
13826
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13827
    }
13828
 \f]
13829
13830
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13831
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13832
 is symmetric.
13833
13834
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13835
 if the pixels in bands are considered to be a sample of the whole population.
13836
 This is consistent with the default of
13837
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13838
 matrix is consistent with what can be obtained with
13839
13840
 \verbatim embed:rst
13841
 .. code-block:: python
13842
13843
     numpy.cov(
13844
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13845
     )
13846
 \endverbatim
13847
13848
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13849
 to be the whole population.
13850
13851
 The caller must provide an already allocated array in padfCovMatrix of size
13852
 at least GDALGetRasterCount() * GDALGetRasterCount().
13853
13854
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13855
 metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13856
 to use them.
13857
13858
 This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13859
13860
 @param hDS Dataset handle.
13861
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13862
                      nBandCount * nBandCount.
13863
 @param nSize Number of elements in output array.
13864
 @param nBandCount Zero for all bands, or number of values in panBandList.
13865
                   Defaults to 0.
13866
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
13867
                    nBandCount values such as panBandList[i] is the index
13868
                    between 1 and GetRasterCount() of a band that must be used
13869
                    in the covariance computation. Defaults to nullptr.
13870
 @param bApproxOK Whether it is acceptable to use a subsample of values.
13871
                  Defaults to false.
13872
 @param bWriteIntoMetadata Whether this method must write
13873
                           STATISTICS_COVARIANCES band metadata items.
13874
                           Defaults to true.
13875
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13876
                              averaging phase of the covariance computation.
13877
                              Defaults to 1.
13878
 @param pfnProgress a function to call to report progress, or NULL.
13879
 @param pProgressData application data to pass to the progress function.
13880
13881
 @return CE_None if successful, or CE_Failure in case of failure
13882
13883
 @since 3.13
13884
13885
 @see GDALDatasetGetInterBandCovarianceMatrix()
13886
 */
13887
CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13888
    GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13889
    const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13890
    int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13891
    void *pProgressData)
13892
0
{
13893
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13894
0
    VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13895
0
    return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13896
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13897
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13898
0
}