Coverage Report

Created: 2026-07-25 06:50

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 != nullptr) != (poGlobalSRS != nullptr)) ||
1414
0
                     (poSRS && !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(GDALDriver::ToHandle(poDriver), pszOptionList,
2520
0
                                aosOptions.List(), "overview creation option",
2521
0
                                osDriver);
2522
0
        }
2523
0
    }
2524
2525
0
    if (nListBands == 0)
2526
0
    {
2527
0
        nListBands = GetRasterCount();
2528
0
        panAllBandList =
2529
0
            static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2530
0
        for (int i = 0; i < nListBands; ++i)
2531
0
            panAllBandList[i] = i + 1;
2532
2533
0
        panBandList = panAllBandList;
2534
0
    }
2535
2536
0
    if (pfnProgress == nullptr)
2537
0
        pfnProgress = GDALDummyProgress;
2538
2539
0
    for (int i = 0; i < nOverviews; ++i)
2540
0
    {
2541
0
        if (panOverviewList[i] <= 0)
2542
0
        {
2543
0
            CPLError(CE_Failure, CPLE_IllegalArg,
2544
0
                     "panOverviewList[%d] = %d is invalid. It must be a "
2545
0
                     "positive value",
2546
0
                     i, panOverviewList[i]);
2547
0
            CPLFree(panAllBandList);
2548
0
            return CE_Failure;
2549
0
        }
2550
0
    }
2551
2552
0
    const CPLErr eErr = IBuildOverviews(
2553
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2554
0
        pfnProgress, pProgressData, aosOptions.List());
2555
2556
0
    if (panAllBandList != nullptr)
2557
0
        CPLFree(panAllBandList);
2558
2559
0
    return eErr;
2560
0
}
2561
2562
/************************************************************************/
2563
/*                         GDALBuildOverviews()                         */
2564
/************************************************************************/
2565
2566
/**
2567
 * \brief Build raster overview(s)
2568
 *
2569
 * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2570
 */
2571
2572
CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2573
                                      const char *pszResampling, int nOverviews,
2574
                                      const int *panOverviewList,
2575
                                      int nListBands, const int *panBandList,
2576
                                      GDALProgressFunc pfnProgress,
2577
                                      void *pProgressData)
2578
2579
0
{
2580
0
    VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2581
2582
0
    return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2583
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2584
0
        pfnProgress, pProgressData, nullptr);
2585
0
}
2586
2587
/************************************************************************/
2588
/*                         GDALBuildOverviews()                         */
2589
/************************************************************************/
2590
2591
/**
2592
 * \brief Build raster overview(s)
2593
 *
2594
 * @see GDALDataset::BuildOverviews()
2595
 * @since GDAL 3.6
2596
 */
2597
2598
CPLErr CPL_STDCALL
2599
GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2600
                     int nOverviews, const int *panOverviewList, int nListBands,
2601
                     const int *panBandList, GDALProgressFunc pfnProgress,
2602
                     void *pProgressData, CSLConstList papszOptions)
2603
2604
0
{
2605
0
    VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2606
2607
0
    return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2608
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2609
0
        pfnProgress, pProgressData, papszOptions);
2610
0
}
2611
2612
/************************************************************************/
2613
/*                          IBuildOverviews()                           */
2614
/*                                                                      */
2615
/*      Default implementation.                                         */
2616
/************************************************************************/
2617
2618
//! @cond Doxygen_Suppress
2619
CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2620
                                    const int *panOverviewList, int nListBands,
2621
                                    const int *panBandList,
2622
                                    GDALProgressFunc pfnProgress,
2623
                                    void *pProgressData,
2624
                                    CSLConstList papszOptions)
2625
2626
0
{
2627
0
    if (oOvManager.IsInitialized())
2628
0
        return oOvManager.BuildOverviews(
2629
0
            nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2630
0
            panBandList, pfnProgress, pProgressData, papszOptions);
2631
0
    else
2632
0
    {
2633
0
        ReportError(CE_Failure, CPLE_NotSupported,
2634
0
                    "BuildOverviews() not supported for this dataset.");
2635
2636
0
        return CE_Failure;
2637
0
    }
2638
0
}
2639
2640
//! @endcond
2641
2642
/************************************************************************/
2643
/*                            AddOverviews()                            */
2644
/*                                                                      */
2645
/*      Default implementation.                                         */
2646
/************************************************************************/
2647
2648
/**
2649
 * \brief Add overview from existing dataset(s)
2650
 *
2651
 * This function creates new overview levels or refresh existing one from
2652
 * the list of provided overview datasets.
2653
 * Source overviews may come from any GDAL supported format, provided they
2654
 * have the same number of bands and geospatial extent than the target
2655
 * dataset.
2656
 *
2657
 * If the operation is not supported for the indicated dataset, then
2658
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
2659
 * CPLE_NotSupported.
2660
 *
2661
 * At time of writing, this method is only implemented for internal overviews
2662
 * of GeoTIFF datasets and external overviews in GeoTIFF format.
2663
 *
2664
 * @param apoSrcOvrDS Vector of source overviews.
2665
 * @param pfnProgress a function to call to report progress, or NULL.
2666
 * @param pProgressData application data to pass to the progress function.
2667
 * @param papszOptions NULL terminated list of options as
2668
 *                     key=value pairs, or NULL. Possible keys are the
2669
 *                     ones returned by
2670
 *                     GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2671
 *
2672
 * @return CE_None on success or CE_Failure if the operation doesn't work.
2673
 * @since 3.12
2674
 */
2675
CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2676
                                 GDALProgressFunc pfnProgress,
2677
                                 void *pProgressData, CSLConstList papszOptions)
2678
0
{
2679
0
    if (oOvManager.IsInitialized())
2680
0
    {
2681
0
        return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2682
0
                                       pProgressData, papszOptions);
2683
0
    }
2684
0
    else
2685
0
    {
2686
0
        ReportError(CE_Failure, CPLE_NotSupported,
2687
0
                    "AddOverviews() not supported for this dataset.");
2688
0
        return CE_Failure;
2689
0
    }
2690
0
}
2691
2692
/************************************************************************/
2693
/*                             IRasterIO()                              */
2694
/*                                                                      */
2695
/*      The default implementation of IRasterIO() is, in the general    */
2696
/*      case to pass the request off to each band objects rasterio      */
2697
/*      methods with appropriate arguments. In some cases, it might     */
2698
/*      choose instead the BlockBasedRasterIO() implementation.         */
2699
/************************************************************************/
2700
2701
//! @cond Doxygen_Suppress
2702
CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2703
                              int nXSize, int nYSize, void *pData,
2704
                              int nBufXSize, int nBufYSize,
2705
                              GDALDataType eBufType, int nBandCount,
2706
                              BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2707
                              GSpacing nLineSpace, GSpacing nBandSpace,
2708
                              GDALRasterIOExtraArg *psExtraArg)
2709
2710
0
{
2711
0
    const char *pszInterleave = nullptr;
2712
2713
0
    CPLAssert(nullptr != pData);
2714
2715
0
    const bool bHasSubpixelShift =
2716
0
        psExtraArg->bFloatingPointWindowValidity &&
2717
0
        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2718
0
        (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2719
2720
0
    if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2721
0
        nBandCount > 1 &&
2722
0
        (pszInterleave = GetMetadataItem(
2723
0
             GDALMD_INTERLEAVE, GDAL_MDD_IMAGE_STRUCTURE)) != nullptr &&
2724
0
        EQUAL(pszInterleave, "PIXEL"))
2725
0
    {
2726
0
        return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2727
0
                                  nBufXSize, nBufYSize, eBufType, nBandCount,
2728
0
                                  panBandMap, nPixelSpace, nLineSpace,
2729
0
                                  nBandSpace, psExtraArg);
2730
0
    }
2731
2732
0
    if (eRWFlag == GF_Read &&
2733
0
        (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2734
0
         psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2735
0
         psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2736
0
         psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2737
0
        !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2738
0
    {
2739
0
        if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2740
0
        {
2741
0
            int bTried = FALSE;
2742
0
            const CPLErr eErr = TryOverviewRasterIO(
2743
0
                eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2744
0
                nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2745
0
                nLineSpace, nBandSpace, psExtraArg, &bTried);
2746
0
            if (bTried)
2747
0
                return eErr;
2748
0
        }
2749
2750
0
        GDALDataType eFirstBandDT = GDT_Unknown;
2751
0
        int nFirstMaskFlags = 0;
2752
0
        GDALRasterBand *poFirstMaskBand = nullptr;
2753
0
        int nOKBands = 0;
2754
2755
        // Check if bands share the same mask band
2756
0
        for (int i = 0; i < nBandCount; ++i)
2757
0
        {
2758
0
            GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2759
0
            if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2760
0
                poBand->GetOverviewCount())
2761
0
            {
2762
                // Could be improved to select the appropriate overview.
2763
0
                break;
2764
0
            }
2765
0
            if (poBand->GetColorTable() != nullptr)
2766
0
            {
2767
0
                break;
2768
0
            }
2769
0
            const GDALDataType eDT = poBand->GetRasterDataType();
2770
0
            if (GDALDataTypeIsComplex(eDT))
2771
0
            {
2772
0
                break;
2773
0
            }
2774
0
            if (i == 0)
2775
0
            {
2776
0
                eFirstBandDT = eDT;
2777
0
                nFirstMaskFlags = poBand->GetMaskFlags();
2778
0
                if (nFirstMaskFlags == GMF_NODATA)
2779
0
                {
2780
                    // The dataset-level resampling code is not ready for nodata
2781
                    // Fallback to band-level resampling
2782
0
                    break;
2783
0
                }
2784
0
                poFirstMaskBand = poBand->GetMaskBand();
2785
0
            }
2786
0
            else
2787
0
            {
2788
0
                if (eDT != eFirstBandDT)
2789
0
                {
2790
0
                    break;
2791
0
                }
2792
0
                int nMaskFlags = poBand->GetMaskFlags();
2793
0
                if (nMaskFlags == GMF_NODATA)
2794
0
                {
2795
                    // The dataset-level resampling code is not ready for nodata
2796
                    // Fallback to band-level resampling
2797
0
                    break;
2798
0
                }
2799
0
                GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2800
0
                if (nFirstMaskFlags == GMF_ALL_VALID &&
2801
0
                    nMaskFlags == GMF_ALL_VALID)
2802
0
                {
2803
                    // Ok.
2804
0
                }
2805
0
                else if (poFirstMaskBand == poMaskBand)
2806
0
                {
2807
                    // Ok.
2808
0
                }
2809
0
                else
2810
0
                {
2811
0
                    break;
2812
0
                }
2813
0
            }
2814
2815
0
            ++nOKBands;
2816
0
        }
2817
2818
0
        GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2819
0
        void *pProgressDataGlobal = psExtraArg->pProgressData;
2820
2821
0
        CPLErr eErr = CE_None;
2822
0
        if (nOKBands > 0)
2823
0
        {
2824
0
            if (nOKBands < nBandCount)
2825
0
            {
2826
0
                psExtraArg->pfnProgress = GDALScaledProgress;
2827
0
                psExtraArg->pProgressData = GDALCreateScaledProgress(
2828
0
                    0.0, static_cast<double>(nOKBands) / nBandCount,
2829
0
                    pfnProgressGlobal, pProgressDataGlobal);
2830
0
                if (psExtraArg->pProgressData == nullptr)
2831
0
                    psExtraArg->pfnProgress = nullptr;
2832
0
            }
2833
2834
0
            eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2835
0
                                     pData, nBufXSize, nBufYSize, eBufType,
2836
0
                                     nOKBands, panBandMap, nPixelSpace,
2837
0
                                     nLineSpace, nBandSpace, psExtraArg);
2838
2839
0
            if (nOKBands < nBandCount)
2840
0
            {
2841
0
                GDALDestroyScaledProgress(psExtraArg->pProgressData);
2842
0
            }
2843
0
        }
2844
0
        if (eErr == CE_None && nOKBands < nBandCount)
2845
0
        {
2846
0
            if (nOKBands > 0)
2847
0
            {
2848
0
                psExtraArg->pfnProgress = GDALScaledProgress;
2849
0
                psExtraArg->pProgressData = GDALCreateScaledProgress(
2850
0
                    static_cast<double>(nOKBands) / nBandCount, 1.0,
2851
0
                    pfnProgressGlobal, pProgressDataGlobal);
2852
0
                if (psExtraArg->pProgressData == nullptr)
2853
0
                    psExtraArg->pfnProgress = nullptr;
2854
0
            }
2855
0
            eErr = BandBasedRasterIO(
2856
0
                eRWFlag, nXOff, nYOff, nXSize, nYSize,
2857
0
                static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2858
0
                nBufYSize, eBufType, nBandCount - nOKBands,
2859
0
                panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2860
0
                psExtraArg);
2861
0
            if (nOKBands > 0)
2862
0
            {
2863
0
                GDALDestroyScaledProgress(psExtraArg->pProgressData);
2864
0
            }
2865
0
        }
2866
2867
0
        psExtraArg->pfnProgress = pfnProgressGlobal;
2868
0
        psExtraArg->pProgressData = pProgressDataGlobal;
2869
2870
0
        return eErr;
2871
0
    }
2872
2873
0
    return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2874
0
                             nBufXSize, nBufYSize, eBufType, nBandCount,
2875
0
                             panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2876
0
                             psExtraArg);
2877
0
}
2878
2879
//! @endcond
2880
2881
/************************************************************************/
2882
/*                         BandBasedRasterIO()                          */
2883
/*                                                                      */
2884
/*      Pass the request off to each band objects rasterio methods with */
2885
/*      appropriate arguments.                                          */
2886
/************************************************************************/
2887
2888
//! @cond Doxygen_Suppress
2889
CPLErr GDALDataset::BandBasedRasterIO(
2890
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2891
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2892
    int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2893
    GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2894
2895
0
{
2896
0
    int iBandIndex;
2897
0
    CPLErr eErr = CE_None;
2898
2899
0
    GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2900
0
    void *pProgressDataGlobal = psExtraArg->pProgressData;
2901
2902
0
    for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2903
0
         ++iBandIndex)
2904
0
    {
2905
0
        GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2906
2907
0
        if (poBand == nullptr)
2908
0
        {
2909
0
            eErr = CE_Failure;
2910
0
            break;
2911
0
        }
2912
2913
0
        GByte *pabyBandData =
2914
0
            static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2915
2916
0
        if (nBandCount > 1)
2917
0
        {
2918
0
            psExtraArg->pfnProgress = GDALScaledProgress;
2919
0
            psExtraArg->pProgressData = GDALCreateScaledProgress(
2920
0
                1.0 * iBandIndex / nBandCount,
2921
0
                1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2922
0
                pProgressDataGlobal);
2923
0
            if (psExtraArg->pProgressData == nullptr)
2924
0
                psExtraArg->pfnProgress = nullptr;
2925
0
        }
2926
2927
0
        eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2928
0
                                 pabyBandData, nBufXSize, nBufYSize, eBufType,
2929
0
                                 nPixelSpace, nLineSpace, psExtraArg);
2930
2931
0
        if (nBandCount > 1)
2932
0
            GDALDestroyScaledProgress(psExtraArg->pProgressData);
2933
0
    }
2934
2935
0
    psExtraArg->pfnProgress = pfnProgressGlobal;
2936
0
    psExtraArg->pProgressData = pProgressDataGlobal;
2937
2938
0
    return eErr;
2939
0
}
2940
2941
//! @endcond
2942
2943
/************************************************************************/
2944
/*               ValidateRasterIOOrAdviseReadParameters()               */
2945
/************************************************************************/
2946
2947
//! @cond Doxygen_Suppress
2948
CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2949
    const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2950
    int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2951
    int nBandCount, const int *panBandMap)
2952
0
{
2953
0
    if (nBands == 0)
2954
0
    {
2955
0
        *pbStopProcessingOnCENone = TRUE;
2956
0
        return CE_None;
2957
0
    }
2958
2959
    /* -------------------------------------------------------------------- */
2960
    /*      Some size values are "noop".  Lets just return to avoid         */
2961
    /*      stressing lower level functions.                                */
2962
    /* -------------------------------------------------------------------- */
2963
0
    if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2964
0
    {
2965
0
        CPLDebug("GDAL",
2966
0
                 "%s skipped for odd window or buffer size.\n"
2967
0
                 "  Window = (%d,%d)x%dx%d\n"
2968
0
                 "  Buffer = %dx%d",
2969
0
                 pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2970
0
                 nBufYSize);
2971
2972
0
        *pbStopProcessingOnCENone = TRUE;
2973
0
        return CE_None;
2974
0
    }
2975
2976
0
    CPLErr eErr = CE_None;
2977
0
    *pbStopProcessingOnCENone = FALSE;
2978
2979
0
    if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2980
0
        nYSize > nRasterYSize - nYOff)
2981
0
    {
2982
0
        ReportError(CE_Failure, CPLE_IllegalArg,
2983
0
                    "Access window out of range in %s.  Requested "
2984
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
2985
0
                    pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2986
0
                    nRasterYSize);
2987
0
        eErr = CE_Failure;
2988
0
    }
2989
2990
0
    if (panBandMap == nullptr && nBandCount > GetRasterCount())
2991
0
    {
2992
0
        ReportError(CE_Failure, CPLE_IllegalArg,
2993
0
                    "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2994
0
                    GetRasterCount());
2995
0
        eErr = CE_Failure;
2996
0
    }
2997
2998
0
    for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2999
0
    {
3000
0
        int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
3001
0
        if (iBand < 1 || iBand > GetRasterCount())
3002
0
        {
3003
0
            ReportError(
3004
0
                CE_Failure, CPLE_IllegalArg,
3005
0
                "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
3006
0
                pszCallingFunc, i, iBand);
3007
0
            eErr = CE_Failure;
3008
0
        }
3009
3010
0
        if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3011
0
        {
3012
0
            ReportError(
3013
0
                CE_Failure, CPLE_IllegalArg,
3014
0
                "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3015
0
                pszCallingFunc, i, iBand);
3016
0
            eErr = CE_Failure;
3017
0
        }
3018
0
    }
3019
3020
0
    return eErr;
3021
0
}
3022
3023
//! @endcond
3024
3025
/************************************************************************/
3026
/*                              RasterIO()                              */
3027
/************************************************************************/
3028
3029
/**
3030
 * \brief Read/write a region of image data from multiple bands.
3031
 *
3032
 * This method allows reading a region of one or more GDALRasterBands from
3033
 * this dataset into a buffer,  or writing data from a buffer into a region
3034
 * of the GDALRasterBands.  It automatically takes care of data type
3035
 * translation if the data type (eBufType) of the buffer is different than
3036
 * that of the GDALRasterBand.
3037
 * The method also takes care of image decimation / replication if the
3038
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
3039
 * region being accessed (nXSize x nYSize).
3040
 *
3041
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3042
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3043
 * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3044
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
3045
 * Or use nLineSpace and a possibly shifted pData value.
3046
 *
3047
 * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3048
 * writing from various organization of buffers.
3049
 *
3050
 * Some formats may efficiently implement decimation into a buffer by
3051
 * reading from lower resolution overview images. The logic of the default
3052
 * implementation in the base class GDALRasterBand is the following one. It
3053
 * computes a target_downscaling_factor from the window of interest and buffer
3054
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3055
 * It then walks through overviews and will select the first one whose
3056
 * downscaling factor is greater than target_downscaling_factor / 1.2.
3057
 *
3058
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3059
 * The relationship between target_downscaling_factor and the select overview
3060
 * level is the following one:
3061
 *
3062
 * target_downscaling_factor  | selected_overview
3063
 * -------------------------  | -----------------
3064
 * ]0,       2 / 1.2]         | full resolution band
3065
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
3066
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
3067
 * ]8 / 1.2, infinity[        | 8x downsampled band
3068
 *
3069
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3070
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3071
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3072
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3073
 * this oversampling threshold defaults to 1. Consequently if there are overviews
3074
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3075
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3076
 *
3077
 * For highest performance full resolution data access, read and write
3078
 * on "block boundaries" as returned by GetBlockSize(), or use the
3079
 * ReadBlock() and WriteBlock() methods.
3080
 *
3081
 * This method is the same as the C GDALDatasetRasterIO() or
3082
 * GDALDatasetRasterIOEx() functions.
3083
 *
3084
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3085
 * write a region of data.
3086
 *
3087
 * @param nXOff The pixel offset to the top left corner of the region
3088
 * of the band to be accessed.  This would be zero to start from the left side.
3089
 *
3090
 * @param nYOff The line offset to the top left corner of the region
3091
 * of the band to be accessed.  This would be zero to start from the top.
3092
 *
3093
 * @param nXSize The width of the region of the band to be accessed in pixels.
3094
 *
3095
 * @param nYSize The height of the region of the band to be accessed in lines.
3096
 *
3097
 * @param pData The buffer into which the data should be read, or from which
3098
 * it should be written.  This buffer must contain at least
3099
 * nBufXSize * nBufYSize * nBandCount words of type eBufType.  It is organized
3100
 * in left to right,top to bottom pixel order.  Spacing is controlled by the
3101
 * nPixelSpace, and nLineSpace parameters.
3102
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3103
 * temporarily modified during the execution of this method (and eventually
3104
 * restored back to its original content), so it is not safe to use a buffer
3105
 * stored in a read-only section of the calling program.
3106
 *
3107
 * @param nBufXSize the width of the buffer image into which the desired region
3108
 * is to be read, or from which it is to be written.
3109
 *
3110
 * @param nBufYSize the height of the buffer image into which the desired
3111
 * region is to be read, or from which it is to be written.
3112
 *
3113
 * @param eBufType the type of the pixel values in the pData data buffer. The
3114
 * pixel values will automatically be translated to/from the GDALRasterBand
3115
 * data type as needed. Most driver implementations will use GDALCopyWords64()
3116
 * to perform data type translation.
3117
 *
3118
 * @param nBandCount the number of bands being read or written.
3119
 *
3120
 * @param panBandMap the list of nBandCount band numbers being read/written.
3121
 * Note band numbers are 1 based. This may be NULL to select the first
3122
 * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3123
 * not "const int*")
3124
 *
3125
 * @param nPixelSpace The byte offset from the start of one pixel value in
3126
 * pData to the start of the next pixel value within a scanline. If defaulted
3127
 * (0) the size of the datatype eBufType is used.
3128
 *
3129
 * @param nLineSpace The byte offset from the start of one scanline in
3130
 * pData to the start of the next. If defaulted (0) the size of the datatype
3131
 * eBufType * nBufXSize is used.
3132
 *
3133
 * @param nBandSpace the byte offset from the start of one bands data to the
3134
 * start of the next. If defaulted (0) the value will be
3135
 * nLineSpace * nBufYSize implying band sequential organization
3136
 * of the data buffer.
3137
 *
3138
 * @param psExtraArg pointer to a GDALRasterIOExtraArg
3139
 * structure with additional arguments to specify resampling and progress
3140
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3141
 * configuration option can also be defined to override the default resampling
3142
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3143
 *
3144
 * @return CE_Failure if the access fails, otherwise CE_None.
3145
 */
3146
3147
CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3148
                             int nXSize, int nYSize, void *pData, int nBufXSize,
3149
                             int nBufYSize, GDALDataType eBufType,
3150
                             int nBandCount, const int *panBandMap,
3151
                             GSpacing nPixelSpace, GSpacing nLineSpace,
3152
                             GSpacing nBandSpace,
3153
                             GDALRasterIOExtraArg *psExtraArg)
3154
3155
0
{
3156
0
    GDALRasterIOExtraArg sExtraArg;
3157
0
    if (psExtraArg == nullptr)
3158
0
    {
3159
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3160
3161
        // 4 below inits are not strictly needed but make Coverity Scan
3162
        // happy
3163
0
        sExtraArg.dfXOff = nXOff;
3164
0
        sExtraArg.dfYOff = nYOff;
3165
0
        sExtraArg.dfXSize = nXSize;
3166
0
        sExtraArg.dfYSize = nYSize;
3167
3168
0
        psExtraArg = &sExtraArg;
3169
0
    }
3170
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
3171
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3172
0
    {
3173
0
        ReportError(CE_Failure, CPLE_AppDefined,
3174
0
                    "Unhandled version of GDALRasterIOExtraArg");
3175
0
        return CE_Failure;
3176
0
    }
3177
3178
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3179
0
                                       nBufYSize);
3180
3181
0
    if (CPL_UNLIKELY(nullptr == pData))
3182
0
    {
3183
0
        ReportError(CE_Failure, CPLE_AppDefined,
3184
0
                    "The buffer into which the data should be read is null");
3185
0
        return CE_Failure;
3186
0
    }
3187
3188
    /* -------------------------------------------------------------------- */
3189
    /*      Do some validation of parameters.                               */
3190
    /* -------------------------------------------------------------------- */
3191
3192
0
    if (CPL_UNLIKELY(static_cast<int>(eRWFlag) != static_cast<int>(GF_Read) &&
3193
0
                     static_cast<int>(eRWFlag) != static_cast<int>(GF_Write)))
3194
0
    {
3195
0
        ReportError(
3196
0
            CE_Failure, CPLE_IllegalArg,
3197
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3198
0
            eRWFlag);
3199
0
        return CE_Failure;
3200
0
    }
3201
3202
0
    if (eRWFlag == GF_Write)
3203
0
    {
3204
0
        if (CPL_UNLIKELY(eAccess != GA_Update))
3205
0
        {
3206
0
            ReportError(CE_Failure, CPLE_AppDefined,
3207
0
                        "Write operation not permitted on dataset opened "
3208
0
                        "in read-only mode");
3209
0
            return CE_Failure;
3210
0
        }
3211
0
    }
3212
3213
0
    int bStopProcessing = FALSE;
3214
0
    CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3215
0
        "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3216
0
        nBufYSize, nBandCount, panBandMap);
3217
0
    if (eErr != CE_None || bStopProcessing)
3218
0
        return eErr;
3219
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3220
0
    {
3221
0
        ReportError(CE_Failure, CPLE_AppDefined,
3222
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
3223
0
        return CE_Failure;
3224
0
    }
3225
3226
    /* -------------------------------------------------------------------- */
3227
    /*      If pixel and line spacing are defaulted assign reasonable      */
3228
    /*      value assuming a packed buffer.                                 */
3229
    /* -------------------------------------------------------------------- */
3230
0
    if (nPixelSpace == 0)
3231
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3232
3233
0
    if (nLineSpace == 0)
3234
0
    {
3235
0
        nLineSpace = nPixelSpace * nBufXSize;
3236
0
    }
3237
3238
0
    if (nBandSpace == 0 && nBandCount > 1)
3239
0
    {
3240
0
        nBandSpace = nLineSpace * nBufYSize;
3241
0
    }
3242
3243
0
    if (panBandMap == nullptr)
3244
0
    {
3245
0
        if (!m_poPrivate)
3246
0
            return CE_Failure;
3247
0
        CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3248
0
        panBandMap = m_poPrivate->m_anBandMap.data();
3249
0
    }
3250
3251
0
    int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3252
3253
    /* -------------------------------------------------------------------- */
3254
    /*      We are being forced to use cached IO instead of a driver        */
3255
    /*      specific implementation.                                        */
3256
    /* -------------------------------------------------------------------- */
3257
0
    if (bForceCachedIO)
3258
0
    {
3259
0
        eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3260
0
                                  nBufXSize, nBufYSize, eBufType, nBandCount,
3261
0
                                  panBandMap, nPixelSpace, nLineSpace,
3262
0
                                  nBandSpace, psExtraArg);
3263
0
    }
3264
3265
    /* -------------------------------------------------------------------- */
3266
    /*      Call the format specific function.                              */
3267
    /* -------------------------------------------------------------------- */
3268
0
    else
3269
0
    {
3270
0
        eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3271
0
                         nBufXSize, nBufYSize, eBufType, nBandCount,
3272
                         // TODO: remove this const_cast once IRasterIO()
3273
                         // takes a const int*
3274
0
                         const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3275
0
                         nBandSpace, psExtraArg);
3276
0
    }
3277
3278
0
    if (bCallLeaveReadWrite)
3279
0
        LeaveReadWrite();
3280
3281
0
    return eErr;
3282
0
}
3283
3284
/************************************************************************/
3285
/*                        GDALDatasetRasterIO()                         */
3286
/************************************************************************/
3287
3288
/**
3289
 * \brief Read/write a region of image data from multiple bands.
3290
 *
3291
 * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3292
 * resolution, progress callback, etc. are needed)
3293
 *
3294
 * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3295
 *
3296
 * @see GDALDataset::RasterIO()
3297
 */
3298
3299
CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3300
                                       int nXOff, int nYOff, int nXSize,
3301
                                       int nYSize, void *pData, int nBufXSize,
3302
                                       int nBufYSize, GDALDataType eBufType,
3303
                                       int nBandCount, const int *panBandMap,
3304
                                       int nPixelSpace, int nLineSpace,
3305
                                       int nBandSpace)
3306
3307
0
{
3308
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3309
3310
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3311
3312
0
    return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3313
0
                          nBufXSize, nBufYSize, eBufType, nBandCount,
3314
0
                          panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3315
0
                          nullptr);
3316
0
}
3317
3318
/************************************************************************/
3319
/*                       GDALDatasetRasterIOEx()                        */
3320
/************************************************************************/
3321
3322
/**
3323
 * \brief Read/write a region of image data from multiple bands.
3324
 *
3325
 * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3326
 *
3327
 * @see GDALDataset::RasterIO()
3328
 */
3329
3330
CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3331
    GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3332
    int nYSize, void *pData, int nBufXSize, int nBufYSize,
3333
    GDALDataType eBufType, int nBandCount, const int *panBandMap,
3334
    GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3335
    GDALRasterIOExtraArg *psExtraArg)
3336
3337
0
{
3338
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3339
3340
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3341
3342
0
    return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3343
0
                          nBufXSize, nBufYSize, eBufType, nBandCount,
3344
0
                          panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3345
0
                          psExtraArg);
3346
0
}
3347
3348
/************************************************************************/
3349
/*                          GetOpenDatasets()                           */
3350
/************************************************************************/
3351
3352
/**
3353
 * \brief Fetch all open GDAL dataset handles.
3354
 *
3355
 * This method is the same as the C function GDALGetOpenDatasets().
3356
 *
3357
 * NOTE: This method is not thread safe.  The returned list may change
3358
 * at any time and it should not be freed.
3359
 *
3360
 * @param pnCount integer into which to place the count of dataset pointers
3361
 * being returned.
3362
 *
3363
 * @return a pointer to an array of dataset handles.
3364
 */
3365
3366
GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3367
3368
0
{
3369
0
    CPLMutexHolderD(&hDLMutex);
3370
3371
0
    if (poAllDatasetMap == nullptr)
3372
0
    {
3373
0
        *pnCount = 0;
3374
0
        return nullptr;
3375
0
    }
3376
3377
0
    *pnCount = static_cast<int>(poAllDatasetMap->size());
3378
0
    ppDatasets = static_cast<GDALDataset **>(
3379
0
        CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3380
0
    std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3381
0
    for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3382
0
        ppDatasets[i] = oIter->first;
3383
0
    return ppDatasets;
3384
0
}
3385
3386
/************************************************************************/
3387
/*                        GDALGetOpenDatasets()                         */
3388
/************************************************************************/
3389
3390
/**
3391
 * \brief Fetch all open GDAL dataset handles.
3392
 *
3393
 * @see GDALDataset::GetOpenDatasets()
3394
 */
3395
3396
void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3397
3398
0
{
3399
0
    VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3400
0
    VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3401
3402
0
    *ppahDSList =
3403
0
        reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3404
0
}
3405
3406
/************************************************************************/
3407
/*                     GDALCleanOpenDatasetsList()                      */
3408
/************************************************************************/
3409
3410
// Useful when called from the child of a fork(), to avoid closing
3411
// the datasets of the parent at the child termination.
3412
void GDALNullifyOpenDatasetsList()
3413
0
{
3414
0
    poAllDatasetMap = nullptr;
3415
0
    phSharedDatasetSet = nullptr;
3416
0
    ppDatasets = nullptr;
3417
0
    hDLMutex = nullptr;
3418
0
}
3419
3420
/************************************************************************/
3421
/*                           GDALGetAccess()                            */
3422
/************************************************************************/
3423
3424
/**
3425
 * \brief Return access flag
3426
 *
3427
 * @see GDALDataset::GetAccess()
3428
 */
3429
3430
int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3431
0
{
3432
0
    VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3433
3434
0
    return GDALDataset::FromHandle(hDS)->GetAccess();
3435
0
}
3436
3437
/************************************************************************/
3438
/*                             AdviseRead()                             */
3439
/************************************************************************/
3440
3441
/**
3442
 * \brief Advise driver of upcoming read requests.
3443
 *
3444
 * Some GDAL drivers operate more efficiently if they know in advance what
3445
 * set of upcoming read requests will be made.  The AdviseRead() method allows
3446
 * an application to notify the driver of the region and bands of interest,
3447
 * and at what resolution the region will be read.
3448
 *
3449
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
3450
 * accelerate access via some drivers.
3451
 *
3452
 * Depending on call paths, drivers might receive several calls to
3453
 * AdviseRead() with the same parameters.
3454
 *
3455
 * @param nXOff The pixel offset to the top left corner of the region
3456
 * of the band to be accessed.  This would be zero to start from the left side.
3457
 *
3458
 * @param nYOff The line offset to the top left corner of the region
3459
 * of the band to be accessed.  This would be zero to start from the top.
3460
 *
3461
 * @param nXSize The width of the region of the band to be accessed in pixels.
3462
 *
3463
 * @param nYSize The height of the region of the band to be accessed in lines.
3464
 *
3465
 * @param nBufXSize the width of the buffer image into which the desired region
3466
 * is to be read, or from which it is to be written.
3467
 *
3468
 * @param nBufYSize the height of the buffer image into which the desired
3469
 * region is to be read, or from which it is to be written.
3470
 *
3471
 * @param eBufType the type of the pixel values in the pData data buffer.  The
3472
 * pixel values will automatically be translated to/from the GDALRasterBand
3473
 * data type as needed.
3474
 *
3475
 * @param nBandCount the number of bands being read or written.
3476
 *
3477
 * @param panBandMap the list of nBandCount band numbers being read/written.
3478
 * Note band numbers are 1 based.   This may be NULL to select the first
3479
 * nBandCount bands.
3480
 *
3481
 * @param papszOptions a list of name=value strings with special control
3482
 * options.  Normally this is NULL.
3483
 *
3484
 * @return CE_Failure if the request is invalid and CE_None if it works or
3485
 * is ignored.
3486
 */
3487
3488
CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3489
                               int nBufXSize, int nBufYSize,
3490
                               GDALDataType eBufType, int nBandCount,
3491
                               int *panBandMap, CSLConstList papszOptions)
3492
3493
0
{
3494
    /* -------------------------------------------------------------------- */
3495
    /*      Do some validation of parameters.                               */
3496
    /* -------------------------------------------------------------------- */
3497
0
    int bStopProcessing = FALSE;
3498
0
    CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3499
0
        "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3500
0
        nBufXSize, nBufYSize, nBandCount, panBandMap);
3501
0
    if (eErr != CE_None || bStopProcessing)
3502
0
        return eErr;
3503
3504
0
    for (int iBand = 0; iBand < nBandCount; ++iBand)
3505
0
    {
3506
0
        GDALRasterBand *poBand = nullptr;
3507
3508
0
        if (panBandMap == nullptr)
3509
0
            poBand = GetRasterBand(iBand + 1);
3510
0
        else
3511
0
            poBand = GetRasterBand(panBandMap[iBand]);
3512
3513
0
        if (poBand == nullptr)
3514
0
            return CE_Failure;
3515
3516
0
        eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3517
0
                                  nBufYSize, eBufType, papszOptions);
3518
3519
0
        if (eErr != CE_None)
3520
0
            return eErr;
3521
0
    }
3522
3523
0
    return CE_None;
3524
0
}
3525
3526
/************************************************************************/
3527
/*                       GDALDatasetAdviseRead()                        */
3528
/************************************************************************/
3529
3530
/**
3531
 * \brief Advise driver of upcoming read requests.
3532
 *
3533
 * @see GDALDataset::AdviseRead()
3534
 */
3535
CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3536
                                         int nXSize, int nYSize, int nBufXSize,
3537
                                         int nBufYSize, GDALDataType eDT,
3538
                                         int nBandCount, int *panBandMap,
3539
                                         CSLConstList papszOptions)
3540
3541
0
{
3542
0
    VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3543
3544
0
    return GDALDataset::FromHandle(hDS)->AdviseRead(
3545
0
        nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3546
0
        panBandMap, const_cast<char **>(papszOptions));
3547
0
}
3548
3549
/************************************************************************/
3550
/*                       GDALAntiRecursionStruct                        */
3551
/************************************************************************/
3552
3553
// Prevent infinite recursion.
3554
struct GDALAntiRecursionStruct
3555
{
3556
    struct DatasetContext
3557
    {
3558
        std::string osFilename;
3559
        int nOpenFlags;
3560
        std::string osAllowedDrivers;
3561
3562
        DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3563
                       const std::string &osAllowedDriversIn)
3564
0
            : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3565
0
              osAllowedDrivers(osAllowedDriversIn)
3566
0
        {
3567
0
        }
3568
    };
3569
3570
    struct DatasetContextCompare
3571
    {
3572
        bool operator()(const DatasetContext &lhs,
3573
                        const DatasetContext &rhs) const
3574
0
        {
3575
0
            return lhs.osFilename < rhs.osFilename ||
3576
0
                   (lhs.osFilename == rhs.osFilename &&
3577
0
                    (lhs.nOpenFlags < rhs.nOpenFlags ||
3578
0
                     (lhs.nOpenFlags == rhs.nOpenFlags &&
3579
0
                      lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3580
0
        }
3581
    };
3582
3583
    ~GDALAntiRecursionStruct()
3584
0
    {
3585
0
        CPLAssert(aosDatasetNamesWithFlags.empty());
3586
0
        CPLAssert(nRecLevel == 0);
3587
0
        CPLAssert(m_oMapDepth.empty());
3588
0
    }
3589
3590
    std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3591
    int nRecLevel = 0;
3592
    std::map<std::string, int> m_oMapDepth{};
3593
};
3594
3595
#ifdef _WIN32
3596
// Currently thread_local and C++ objects don't work well with DLL on Windows
3597
static void FreeAntiRecursionOpen(void *pData)
3598
{
3599
    delete static_cast<GDALAntiRecursionStruct *>(pData);
3600
}
3601
3602
static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3603
{
3604
    static GDALAntiRecursionStruct dummy;
3605
    int bMemoryErrorOccurred = false;
3606
    void *pData =
3607
        CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3608
    if (bMemoryErrorOccurred)
3609
    {
3610
        return dummy;
3611
    }
3612
    if (pData == nullptr)
3613
    {
3614
        auto pAntiRecursion = new GDALAntiRecursionStruct();
3615
        CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3616
                                FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3617
        if (bMemoryErrorOccurred)
3618
        {
3619
            delete pAntiRecursion;
3620
            return dummy;
3621
        }
3622
        return *pAntiRecursion;
3623
    }
3624
    return *static_cast<GDALAntiRecursionStruct *>(pData);
3625
}
3626
#else
3627
static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3628
3629
static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3630
0
{
3631
0
    return g_tls_antiRecursion;
3632
0
}
3633
#endif
3634
3635
//! @cond Doxygen_Suppress
3636
GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3637
0
    : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3638
0
      m_osIdentifier(osIdentifier),
3639
0
      m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3640
0
{
3641
0
    CPLAssert(!osIdentifier.empty());
3642
0
}
3643
3644
GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3645
    const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3646
0
    : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3647
0
      m_osIdentifier(osIdentifier.empty()
3648
0
                         ? osIdentifier
3649
0
                         : other.m_osIdentifier + osIdentifier),
3650
0
      m_nDepth(m_osIdentifier.empty()
3651
0
                   ? 0
3652
0
                   : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3653
0
{
3654
0
}
3655
3656
GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3657
0
{
3658
0
    if (!m_osIdentifier.empty())
3659
0
    {
3660
0
        auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3661
0
        CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3662
0
        if (--(oIter->second) == 0)
3663
0
            m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3664
0
    }
3665
0
}
3666
3667
//! @endcond
3668
3669
/************************************************************************/
3670
/*                            GetFileList()                             */
3671
/************************************************************************/
3672
3673
/**
3674
 * \brief Fetch files forming dataset.
3675
 *
3676
 * Returns a list of files believed to be part of this dataset.  If it returns
3677
 * an empty list of files it means there is believed to be no local file
3678
 * system files associated with the dataset (for instance a virtual dataset).
3679
 * The returned file list is owned by the caller and should be deallocated
3680
 * with CSLDestroy().
3681
 *
3682
 * The returned filenames will normally be relative or absolute paths
3683
 * depending on the path used to originally open the dataset.  The strings
3684
 * will be UTF-8 encoded.
3685
 *
3686
 * This method is the same as the C GDALGetFileList() function.
3687
 *
3688
 * @return NULL or a NULL terminated array of file names.
3689
 */
3690
3691
char **GDALDataset::GetFileList()
3692
3693
0
{
3694
0
    CPLString osMainFilename = GetDescription();
3695
0
    VSIStatBufL sStat;
3696
3697
0
    GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3698
0
    GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3699
0
                                                        std::string());
3700
0
    auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3701
0
    if (cpl::contains(aosDatasetList, datasetCtxt))
3702
0
        return nullptr;
3703
3704
    /* -------------------------------------------------------------------- */
3705
    /*      Is the main filename even a real filesystem object?             */
3706
    /* -------------------------------------------------------------------- */
3707
0
    int bMainFileReal =
3708
0
        VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3709
3710
    /* -------------------------------------------------------------------- */
3711
    /*      Form new list.                                                  */
3712
    /* -------------------------------------------------------------------- */
3713
0
    char **papszList = nullptr;
3714
3715
0
    if (bMainFileReal)
3716
0
        papszList = CSLAddString(papszList, osMainFilename);
3717
3718
0
    if (sAntiRecursion.nRecLevel == 100)
3719
0
    {
3720
0
        CPLError(CE_Failure, CPLE_AppDefined,
3721
0
                 "GetFileList() called with too many recursion levels");
3722
0
        return papszList;
3723
0
    }
3724
0
    ++sAntiRecursion.nRecLevel;
3725
3726
    /* -------------------------------------------------------------------- */
3727
    /*      Do we have a known overview file?                               */
3728
    /* -------------------------------------------------------------------- */
3729
0
    if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3730
0
    {
3731
0
        auto iter = aosDatasetList.insert(datasetCtxt).first;
3732
0
        char **papszOvrList = oOvManager.poODS->GetFileList();
3733
0
        papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3734
0
        CSLDestroy(papszOvrList);
3735
0
        aosDatasetList.erase(iter);
3736
0
    }
3737
3738
    /* -------------------------------------------------------------------- */
3739
    /*      Do we have a known mask file?                                   */
3740
    /* -------------------------------------------------------------------- */
3741
0
    if (oOvManager.HaveMaskFile())
3742
0
    {
3743
0
        auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3744
0
        for (const char *pszFile :
3745
0
             CPLStringList(oOvManager.poMaskDS->GetFileList()))
3746
0
        {
3747
0
            if (CSLFindString(papszList, pszFile) < 0)
3748
0
                papszList = CSLAddString(papszList, pszFile);
3749
0
        }
3750
0
        aosDatasetList.erase(iter);
3751
0
    }
3752
3753
0
    --sAntiRecursion.nRecLevel;
3754
3755
0
    return papszList;
3756
0
}
3757
3758
/************************************************************************/
3759
/*                          GDALGetFileList()                           */
3760
/************************************************************************/
3761
3762
/**
3763
 * \brief Fetch files forming dataset.
3764
 *
3765
 * @see GDALDataset::GetFileList()
3766
 */
3767
3768
char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3769
3770
0
{
3771
0
    VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3772
3773
0
    return GDALDataset::FromHandle(hDS)->GetFileList();
3774
0
}
3775
3776
/************************************************************************/
3777
/*                           CreateMaskBand()                           */
3778
/************************************************************************/
3779
3780
/**
3781
 * \brief Adds a mask band to the dataset
3782
 *
3783
 * The default implementation of the CreateMaskBand() method is implemented
3784
 * based on similar rules to the .ovr handling implemented using the
3785
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3786
 * be created with the same basename as the original file, and it will have
3787
 * one band.
3788
 * The mask images will be deflate compressed tiled images with the same
3789
 * block size as the original image if possible.
3790
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3791
 * level, where xx matches the band number of a band of the main dataset. The
3792
 * value of those items will be the one of the nFlagsIn parameter.
3793
 *
3794
 * Note that if you got a mask band with a previous call to GetMaskBand(), it
3795
 * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3796
 * again.
3797
 *
3798
 *
3799
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3800
 *                 GMF_PER_DATASET will be always set, even if not explicitly
3801
 *                 specified.
3802
 * @return CE_None on success or CE_Failure on an error.
3803
 *
3804
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3805
 * @see GDALRasterBand::CreateMaskBand()
3806
 *
3807
 */
3808
CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3809
3810
0
{
3811
0
    if (oOvManager.IsInitialized())
3812
0
    {
3813
0
        CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3814
0
        if (eErr != CE_None)
3815
0
            return eErr;
3816
3817
        // Invalidate existing raster band masks.
3818
0
        for (int i = 0; i < nBands; ++i)
3819
0
        {
3820
0
            GDALRasterBand *poBand = papoBands[i];
3821
0
            poBand->poMask.reset();
3822
0
        }
3823
3824
0
        return CE_None;
3825
0
    }
3826
3827
0
    ReportError(CE_Failure, CPLE_NotSupported,
3828
0
                "CreateMaskBand() not supported for this dataset.");
3829
3830
0
    return CE_Failure;
3831
0
}
3832
3833
/************************************************************************/
3834
/*                     GDALCreateDatasetMaskBand()                      */
3835
/************************************************************************/
3836
3837
/**
3838
 * \brief Adds a mask band to the dataset
3839
 * @see GDALDataset::CreateMaskBand()
3840
 */
3841
CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3842
3843
0
{
3844
0
    VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3845
3846
0
    return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3847
0
}
3848
3849
/************************************************************************/
3850
/*                              GDALOpen()                              */
3851
/************************************************************************/
3852
3853
/**
3854
 * \brief Open a raster file as a GDALDataset.
3855
 *
3856
 * This function will try to open the passed file, or virtual dataset
3857
 * name by invoking the Open method of each registered GDALDriver in turn.
3858
 * The first successful open will result in a returned dataset.  If all
3859
 * drivers fail then NULL is returned and an error is issued.
3860
 *
3861
 * Several recommendations :
3862
 * <ul>
3863
 * <li>If you open a dataset object with GA_Update access, it is not recommended
3864
 * to open a new dataset on the same underlying file.</li>
3865
 * <li>The returned dataset should only be accessed by one thread at a time. If
3866
 * you want to use it from different threads, you must add all necessary code
3867
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
3868
 * as GeoTIFF, maintain internal state variables that are updated each time a
3869
 * new block is read, thus preventing concurrent use.) </li>
3870
 * </ul>
3871
 *
3872
 * For drivers supporting the VSI virtual file API, it is possible to open a
3873
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3874
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3875
 * server (see VSIInstallCurlFileHandler())
3876
 *
3877
 * \sa GDALOpenShared()
3878
 * \sa GDALOpenEx()
3879
 *
3880
 * @param pszFilename the name of the file to access.  In the case of
3881
 * exotic drivers this may not refer to a physical file, but instead contain
3882
 * information for the driver on how to access a dataset.  It should be in UTF-8
3883
 * encoding.
3884
 *
3885
 * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
3886
 * drivers support only read only access.
3887
 *
3888
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
3889
 * this handle can be cast to a GDALDataset *.
3890
 */
3891
3892
GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3893
3894
0
{
3895
0
    const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3896
0
    const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3897
0
    GDALDatasetH hDataset =
3898
0
        GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3899
0
    return hDataset;
3900
0
}
3901
3902
/************************************************************************/
3903
/*                            GetSharedDS()                             */
3904
/************************************************************************/
3905
3906
static GDALDataset *GetSharedDS(const char *pszFilename,
3907
                                unsigned int nOpenFlags,
3908
                                const char *const *papszOpenOptions)
3909
0
{
3910
0
    CPLMutexHolderD(&hDLMutex);
3911
3912
0
    if (phSharedDatasetSet != nullptr)
3913
0
    {
3914
0
        const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3915
0
        SharedDatasetCtxt sStruct;
3916
3917
0
        sStruct.nPID = nThisPID;
3918
0
        sStruct.pszDescription = const_cast<char *>(pszFilename);
3919
0
        sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3920
0
        std::string osConcatenatedOpenOptions =
3921
0
            GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3922
0
        sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3923
0
        sStruct.poDS = nullptr;
3924
0
        SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3925
0
            CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3926
0
        if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3927
0
        {
3928
0
            sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3929
0
            psStruct = static_cast<SharedDatasetCtxt *>(
3930
0
                CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3931
0
        }
3932
0
        if (psStruct)
3933
0
        {
3934
0
            return psStruct->poDS;
3935
0
        }
3936
0
    }
3937
0
    return nullptr;
3938
0
}
3939
3940
/************************************************************************/
3941
/*                             GDALOpenEx()                             */
3942
/************************************************************************/
3943
3944
/**
3945
 * \brief Open a raster or vector file as a GDALDataset.
3946
 *
3947
 * This function will try to open the passed file, or virtual dataset
3948
 * name by invoking the Open method of each registered GDALDriver in turn.
3949
 * The first successful open will result in a returned dataset.  If all
3950
 * drivers fail then NULL is returned and an error is issued.
3951
 *
3952
 * Several recommendations :
3953
 * <ul>
3954
 * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3955
 * recommended to open a new dataset on the same underlying file.</li>
3956
 * <li>The returned dataset should only be accessed by one thread at a time. If
3957
 * you want to use it from different threads, you must add all necessary code
3958
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
3959
 * as GeoTIFF, maintain internal state variables that are updated each time a
3960
 * new block is read, thus preventing concurrent use.) </li>
3961
 * </ul>
3962
 *
3963
 * For drivers supporting the VSI virtual file API, it is possible to open a
3964
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3965
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3966
 * server (see VSIInstallCurlFileHandler())
3967
 *
3968
 * In order to reduce the need for searches through the operating system
3969
 * file system machinery, it is possible to give an optional list of files with
3970
 * the papszSiblingFiles parameter.
3971
 * This is the list of all files at the same level in the file system as the
3972
 * target file, including the target file. The filenames must not include any
3973
 * path components, are essentially just the output of VSIReadDir() on the
3974
 * parent directory. If the target object does not have filesystem semantics
3975
 * then the file list should be NULL.
3976
 *
3977
 * @param pszFilename the name of the file to access.  In the case of
3978
 * exotic drivers this may not refer to a physical file, but instead contain
3979
 * information for the driver on how to access a dataset.  It should be in UTF-8
3980
 * encoding.
3981
 *
3982
 * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3983
 * through logical or operator.
3984
 * <ul>
3985
 * <li>Driver kind:
3986
 *   <ul>
3987
 *     <li>GDAL_OF_RASTER for raster drivers,</li>
3988
 *     <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3989
 *     <li>GDAL_OF_VECTOR for vector drivers,</li>
3990
 *     <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3991
 *    </ul>
3992
 * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3993
 * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3994
 * | GDAL_OF_GNM is implied.
3995
 * </li>
3996
 * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3997
 * </li>
3998
 * <li>Shared mode: GDAL_OF_SHARED. If set,
3999
 * it allows the sharing of GDALDataset handles for a dataset with other callers
4000
 * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
4001
 * its list of currently open and shared GDALDataset's, and if the
4002
 * GetDescription() name for one exactly matches the pszFilename passed to
4003
 * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
4004
 * from the same thread.
4005
 * </li>
4006
 * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
4007
 * This must be use in combination with GDAL_OF_RASTER, and is mutually
4008
 * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4009
 * GDAL_OF_GNM.
4010
 * </li>
4011
 * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4012
 * a failed attempt to open the file will lead to an error message to be
4013
 * reported.
4014
 * </li>
4015
 * </ul>
4016
 *
4017
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4018
 * terminated list of strings with the driver short names that must be
4019
 * considered.
4020
 * Starting with GDAL 3.13, a string starting with the dash (-) character
4021
 * followed by the driver short name can be used to exclude a driver.
4022
 *
4023
 * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4024
 * options passed to candidate drivers. An option exists for all drivers,
4025
 * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4026
 * The level index starts at 0. The level number can be suffixed by "only" to
4027
 * specify that only this overview level must be visible, and not sub-levels.
4028
 * Open options are validated by default, and a warning is emitted in case the
4029
 * option is not recognized. In some scenarios, it might be not desirable (e.g.
4030
 * when not knowing which driver will open the file), so the special open option
4031
 * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4032
 * that it may not cause a warning if the driver doesn't declare this option.
4033
 * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4034
 * no overviews should be exposed.
4035
 *
4036
 * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4037
 * filenames that are auxiliary to the main filename. If NULL is passed, a
4038
 * probing of the file system will be done.
4039
 *
4040
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
4041
 * this handle can be cast to a GDALDataset *.
4042
 *
4043
 */
4044
4045
GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4046
                                    unsigned int nOpenFlags,
4047
                                    const char *const *papszAllowedDrivers,
4048
                                    const char *const *papszOpenOptions,
4049
                                    const char *const *papszSiblingFiles)
4050
0
{
4051
0
    VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4052
4053
    // Do some sanity checks on incompatible flags with thread-safe mode.
4054
0
    if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4055
0
    {
4056
0
        const struct
4057
0
        {
4058
0
            int nFlag;
4059
0
            const char *pszFlagName;
4060
0
        } asFlags[] = {
4061
0
            {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4062
0
            {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4063
0
            {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4064
0
            {GDAL_OF_GNM, "GDAL_OF_GNM"},
4065
0
        };
4066
4067
0
        for (const auto &asFlag : asFlags)
4068
0
        {
4069
0
            if ((nOpenFlags & asFlag.nFlag) != 0)
4070
0
            {
4071
0
                CPLError(CE_Failure, CPLE_IllegalArg,
4072
0
                         "GDAL_OF_THREAD_SAFE and %s are mutually "
4073
0
                         "exclusive",
4074
0
                         asFlag.pszFlagName);
4075
0
                return nullptr;
4076
0
            }
4077
0
        }
4078
0
    }
4079
4080
    // If no driver kind is specified, assume all are to be probed.
4081
0
    if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4082
0
        nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4083
4084
    /* -------------------------------------------------------------------- */
4085
    /*      In case of shared dataset, first scan the existing list to see  */
4086
    /*      if it could already contain the requested dataset.              */
4087
    /* -------------------------------------------------------------------- */
4088
0
    if (nOpenFlags & GDAL_OF_SHARED)
4089
0
    {
4090
0
        if (nOpenFlags & GDAL_OF_INTERNAL)
4091
0
        {
4092
0
            CPLError(CE_Failure, CPLE_IllegalArg,
4093
0
                     "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4094
0
            return nullptr;
4095
0
        }
4096
4097
0
        auto poSharedDS =
4098
0
            GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4099
0
        if (poSharedDS)
4100
0
        {
4101
0
            poSharedDS->Reference();
4102
0
            return poSharedDS;
4103
0
        }
4104
0
    }
4105
4106
0
    CPLErrorReset();
4107
0
    VSIErrorReset();
4108
4109
    // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4110
    // shared dataset was asked before.
4111
0
    GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4112
4113
0
    return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4114
0
        .release();
4115
0
}
4116
4117
/************************************************************************/
4118
/*                         GDALDataset::Open()                          */
4119
/************************************************************************/
4120
4121
/**
4122
 * \brief Open a raster or vector file as a GDALDataset.
4123
 *
4124
 * This function will use the passed open info on each registered GDALDriver in
4125
 * turn.
4126
 * The first successful open will result in a returned dataset.  If all
4127
 * drivers fail then NULL is returned and an error is issued.
4128
 *
4129
 * Several recommendations :
4130
 * <ul>
4131
 * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4132
 * recommended to open a new dataset on the same underlying file.</li>
4133
 * <li>The returned dataset should only be accessed by one thread at a time. If
4134
 * you want to use it from different threads, you must add all necessary code
4135
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
4136
 * as GeoTIFF, maintain internal state variables that are updated each time a
4137
 * new block is read, thus preventing concurrent use.) </li>
4138
 * </ul>
4139
 *
4140
 * For drivers supporting the VSI virtual file API, it is possible to open a
4141
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4142
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4143
 * server (see VSIInstallCurlFileHandler())
4144
 *
4145
 * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4146
 * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4147
 * If shared dataset is needed, use GDALOpenEx() or the other variant of
4148
 * GDALDataset::Open()
4149
 *
4150
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4151
 * terminated list of strings with the driver short names that must be
4152
 * considered.
4153
 * Starting with GDAL 3.13, a string starting with the dash (-) character
4154
 * followed by the driver short name can be used to exclude a driver.
4155
 *
4156
 * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4157
 * options passed to candidate drivers. An option exists for all drivers,
4158
 * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4159
 * The level index starts at 0. The level number can be suffixed by "only" to
4160
 * specify that only this overview level must be visible, and not sub-levels.
4161
 * Open options are validated by default, and a warning is emitted in case the
4162
 * option is not recognized. In some scenarios, it might be not desirable (e.g.
4163
 * when not knowing which driver will open the file), so the special open option
4164
 * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4165
 * that it may not cause a warning if the driver doesn't declare this option.
4166
 * OVERVIEW_LEVEL=NONE is supported to indicate that
4167
 * no overviews should be exposed.
4168
 *
4169
 * @return A GDALDataset unique pointer or NULL on failure.
4170
 *
4171
 * @since 3.13
4172
 */
4173
4174
std::unique_ptr<GDALDataset>
4175
GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4176
                  const char *const *papszAllowedDrivers,
4177
                  const char *const *papszOpenOptions)
4178
0
{
4179
    // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4180
    // into VSIKERCHUNK_USE_CACHE config option
4181
0
    std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4182
0
    if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4183
0
    {
4184
0
        poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4185
0
            "VSIKERCHUNK_USE_CACHE", "YES", false);
4186
0
    }
4187
4188
0
    GDALDriverManager *poDM = GetGDALDriverManager();
4189
4190
0
    CPLAssert(nullptr != poDM);
4191
4192
0
    GDALOpenInfo &oOpenInfo = *poOpenInfo;
4193
0
    const char *pszFilename = poOpenInfo->pszFilename;
4194
0
    const int nOpenFlags = poOpenInfo->nOpenFlags;
4195
0
    oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4196
4197
0
    GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4198
0
    if (sAntiRecursion.nRecLevel == 100)
4199
0
    {
4200
0
        CPLError(CE_Failure, CPLE_AppDefined,
4201
0
                 "GDALOpen() called with too many recursion levels");
4202
0
        return nullptr;
4203
0
    }
4204
4205
0
    std::string osAllowedDrivers;
4206
0
    for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4207
0
        osAllowedDrivers += pszDriverName;
4208
0
    auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4209
0
        std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4210
0
    if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4211
0
    {
4212
0
        CPLError(CE_Failure, CPLE_AppDefined,
4213
0
                 "GDALOpen() called on %s recursively", pszFilename);
4214
0
        return nullptr;
4215
0
    }
4216
4217
    // Remove leading @ if present.
4218
0
    char **papszOpenOptionsCleaned =
4219
0
        CSLDuplicate(const_cast<char **>(papszOpenOptions));
4220
0
    for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4221
0
         ++papszIter)
4222
0
    {
4223
0
        char *pszOption = *papszIter;
4224
0
        if (pszOption[0] == '@')
4225
0
            memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4226
0
    }
4227
4228
0
    oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4229
0
    oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4230
4231
0
#ifdef OGRAPISPY_ENABLED
4232
0
    const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4233
0
    const int iSnapshot =
4234
0
        (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4235
0
            ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4236
0
            : INT_MIN;
4237
0
#endif
4238
4239
0
    const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4240
0
    GDALDriver *poMissingPluginDriver = nullptr;
4241
0
    std::vector<GDALDriver *> apoSecondPassDrivers;
4242
4243
    // Lookup of matching driver for dataset can involve up to 2 passes:
4244
    // - in the first pass, all drivers that are compabile of the request mode
4245
    //   (raster/vector/etc.) are probed using their Identify() method if it
4246
    //   exists. If the Identify() method returns FALSE, the driver is skipped.
4247
    //   If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4248
    //   driver is a deferred-loading plugin, it is added to the
4249
    //   apoSecondPassDrivers list for potential later probing, and execution
4250
    //   continues to the next driver in the list.
4251
    //   Otherwise if Identify() returns non-FALSE, the Open() method is used.
4252
    //   If Open() returns a non-NULL dataset, the loop stops and it is
4253
    //   returned. Otherwise looping over remaining drivers continues.
4254
    // - the second pass is optional, only if at least one driver was added
4255
    //   into apoSecondPassDrivers during the first pass. It is similar
4256
    //   to the first pass except it runs only on apoSecondPassDrivers drivers.
4257
    //   And the Open() method of such drivers is used, causing them to be
4258
    //   loaded for real.
4259
0
    int iPass = 1;
4260
0
retry:
4261
0
    for (int iDriver = 0;
4262
0
         iDriver < (iPass == 1 ? nDriverCount
4263
0
                               : static_cast<int>(apoSecondPassDrivers.size()));
4264
0
         ++iDriver)
4265
0
    {
4266
0
        GDALDriver *poDriver =
4267
0
            iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4268
0
                       : apoSecondPassDrivers[iDriver];
4269
0
        const char *pszDriverName = GDALGetDriverShortName(poDriver);
4270
0
        if (pszDriverName && papszAllowedDrivers)
4271
0
        {
4272
0
            bool bDriverMatchedPositively = false;
4273
0
            bool bDriverMatchedNegatively = false;
4274
0
            bool bOnlyExcludedDrivers = true;
4275
0
            for (const char *pszAllowedDriver :
4276
0
                 cpl::Iterate(papszAllowedDrivers))
4277
0
            {
4278
0
                if (pszAllowedDriver[0] != '-')
4279
0
                    bOnlyExcludedDrivers = false;
4280
0
                if (EQUAL(pszAllowedDriver, pszDriverName))
4281
0
                {
4282
0
                    bDriverMatchedPositively = true;
4283
0
                }
4284
0
                else if (pszAllowedDriver[0] == '-' &&
4285
0
                         EQUAL(pszAllowedDriver + 1, pszDriverName))
4286
0
                {
4287
0
                    bDriverMatchedNegatively = true;
4288
0
                    break;
4289
0
                }
4290
0
            }
4291
0
            if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4292
0
                bDriverMatchedNegatively)
4293
0
            {
4294
0
                continue;
4295
0
            }
4296
0
        }
4297
4298
0
        if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4299
0
            continue;
4300
4301
0
        if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4302
0
            (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4303
0
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4304
0
            continue;
4305
0
        if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4306
0
            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4307
0
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4308
0
            continue;
4309
0
        if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4310
0
            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4311
0
            poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4312
0
            continue;
4313
4314
        // Remove general OVERVIEW_LEVEL open options from list before passing
4315
        // it to the driver, if it isn't a driver specific option already.
4316
0
        char **papszTmpOpenOptions = nullptr;
4317
0
        char **papszTmpOpenOptionsToValidate = nullptr;
4318
0
        char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4319
0
        if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4320
0
                nullptr &&
4321
0
            !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4322
0
        {
4323
0
            papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4324
0
            papszTmpOpenOptions =
4325
0
                CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4326
0
            oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4327
4328
0
            papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4329
0
            papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4330
0
                                                     "OVERVIEW_LEVEL", nullptr);
4331
0
            papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4332
0
        }
4333
4334
0
        const int nIdentifyRes =
4335
0
            poDriver->pfnIdentifyEx
4336
0
                ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4337
0
            : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4338
0
                                    : GDAL_IDENTIFY_UNKNOWN;
4339
0
        if (nIdentifyRes == FALSE)
4340
0
        {
4341
0
            CSLDestroy(papszTmpOpenOptions);
4342
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4343
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4344
0
            continue;
4345
0
        }
4346
0
        else if (iPass == 1 && nIdentifyRes < 0 &&
4347
0
                 poDriver->pfnOpen == nullptr &&
4348
0
                 poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4349
0
        {
4350
            // Not loaded plugin
4351
0
            apoSecondPassDrivers.push_back(poDriver);
4352
0
            CSLDestroy(papszTmpOpenOptions);
4353
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4354
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4355
0
            continue;
4356
0
        }
4357
4358
0
        const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4359
0
        if (bIdentifyRes)
4360
0
        {
4361
0
            GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4362
0
        }
4363
4364
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4365
0
        const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4366
0
        CPLErrorReset();
4367
0
#endif
4368
4369
0
        sAntiRecursion.nRecLevel++;
4370
0
        sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4371
4372
0
        GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4373
4374
0
        sAntiRecursion.nRecLevel--;
4375
0
        sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4376
4377
0
        if (poDriver->pfnOpen != nullptr)
4378
0
        {
4379
            // If we couldn't determine for sure with Identify() (it returned
4380
            // -1), but Open() managed to open the file, post validate options.
4381
0
            if (poDS != nullptr &&
4382
0
                (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4383
0
                !bIdentifyRes)
4384
0
            {
4385
0
                GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4386
0
            }
4387
0
        }
4388
0
        else if (poDriver->pfnOpenWithDriverArg != nullptr)
4389
0
        {
4390
            // do nothing
4391
0
        }
4392
0
        else if (bIdentifyRes &&
4393
0
                 poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4394
0
        {
4395
0
            if (!poMissingPluginDriver)
4396
0
            {
4397
0
                poMissingPluginDriver = poDriver;
4398
0
            }
4399
0
        }
4400
0
        else
4401
0
        {
4402
            // should not happen given the GDAL_DCAP_OPEN check
4403
0
            CSLDestroy(papszTmpOpenOptions);
4404
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4405
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4406
0
            continue;
4407
0
        }
4408
4409
0
        CSLDestroy(papszTmpOpenOptions);
4410
0
        CSLDestroy(papszTmpOpenOptionsToValidate);
4411
0
        oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4412
4413
0
        if (poDS != nullptr)
4414
0
        {
4415
0
            if (poDS->papszOpenOptions == nullptr)
4416
0
            {
4417
0
                poDS->papszOpenOptions = papszOpenOptionsCleaned;
4418
0
                papszOpenOptionsCleaned = nullptr;
4419
0
            }
4420
4421
            // Deal with generic OVERVIEW_LEVEL open option, unless it is
4422
            // driver specific.
4423
0
            if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4424
0
                    nullptr &&
4425
0
                !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4426
0
            {
4427
0
                CPLString osVal(
4428
0
                    CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4429
0
                const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4430
0
                const bool bThisLevelOnly =
4431
0
                    nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4432
0
                GDALDataset *poOvrDS =
4433
0
                    GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4434
0
                if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4435
0
                {
4436
0
                    if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4437
0
                    {
4438
0
                        CPLError(
4439
0
                            CE_Warning, CPLE_NotSupported,
4440
0
                            "A dataset opened by GDALOpenShared should have "
4441
0
                            "the same filename (%s) "
4442
0
                            "and description (%s)",
4443
0
                            pszFilename, poDS->GetDescription());
4444
0
                    }
4445
0
                    else
4446
0
                    {
4447
0
                        CSLDestroy(poDS->papszOpenOptions);
4448
0
                        poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4449
0
                        poDS->papszOpenOptions = CSLSetNameValue(
4450
0
                            poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4451
0
                    }
4452
0
                }
4453
0
                poDS->ReleaseRef();
4454
0
                poDS = poOvrDS;
4455
0
                if (poDS == nullptr)
4456
0
                {
4457
0
                    if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4458
0
                    {
4459
0
                        CPLError(CE_Failure, CPLE_OpenFailed,
4460
0
                                 "Cannot open overview level %d of %s",
4461
0
                                 nOvrLevel, pszFilename);
4462
0
                    }
4463
0
                }
4464
0
                else
4465
0
                {
4466
                    // For thread-safe opening, currently poDS is what will be
4467
                    // the "master" dataset owned by the thread-safe dataset
4468
                    // returned to the user, hence we do not register it as a
4469
                    // visible one in the open dataset list, or mark it as shared.
4470
0
                    if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4471
0
                        !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4472
0
                    {
4473
0
                        poDS->AddToDatasetOpenList();
4474
0
                    }
4475
0
                    if (nOpenFlags & GDAL_OF_SHARED)
4476
0
                    {
4477
0
                        CSLDestroy(poDS->papszOpenOptions);
4478
0
                        poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4479
0
                        poDS->nOpenFlags = nOpenFlags;
4480
0
                        if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4481
0
                            poDS->MarkAsShared();
4482
0
                    }
4483
0
                }
4484
0
            }
4485
0
            else if (nOpenFlags & GDAL_OF_SHARED)
4486
0
            {
4487
0
                if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4488
0
                {
4489
0
                    CPLError(CE_Warning, CPLE_NotSupported,
4490
0
                             "A dataset opened by GDALOpenShared should have "
4491
0
                             "the same filename (%s) "
4492
0
                             "and description (%s)",
4493
0
                             pszFilename, poDS->GetDescription());
4494
0
                }
4495
0
                else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4496
0
                {
4497
                    // For thread-safe opening, currently poDS is what will be
4498
                    // the "master" dataset owned by the thread-safe dataset
4499
                    // returned to the user, hence we do not or mark it as shared.
4500
0
                    poDS->MarkAsShared();
4501
0
                }
4502
0
            }
4503
4504
0
            VSIErrorReset();
4505
4506
0
            CSLDestroy(papszOpenOptionsCleaned);
4507
4508
0
#ifdef OGRAPISPY_ENABLED
4509
0
            if (iSnapshot != INT_MIN)
4510
0
            {
4511
0
                GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4512
0
                OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4513
0
                poDS = GDALDataset::FromHandle(hDS);
4514
0
            }
4515
0
#endif
4516
4517
0
            if (poDS)
4518
0
            {
4519
0
                poDS->m_bCanBeReopened = true;
4520
4521
0
                if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4522
0
                {
4523
0
                    poDS =
4524
0
                        GDALGetThreadSafeDataset(
4525
0
                            std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4526
0
                            .release();
4527
0
                    if (poDS)
4528
0
                    {
4529
0
                        poDS->m_bCanBeReopened = true;
4530
0
                        poDS->poDriver = poDriver;
4531
0
                        poDS->nOpenFlags = nOpenFlags;
4532
0
                        if (!(nOpenFlags & GDAL_OF_INTERNAL))
4533
0
                            poDS->AddToDatasetOpenList();
4534
0
                        if (nOpenFlags & GDAL_OF_SHARED)
4535
0
                            poDS->MarkAsShared();
4536
0
                    }
4537
0
                }
4538
0
            }
4539
4540
0
            return std::unique_ptr<GDALDataset>(poDS);
4541
0
        }
4542
4543
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4544
0
        if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4545
0
        {
4546
            // In case the file descriptor was "consumed" by a driver
4547
            // that ultimately failed, re-open it for next drivers.
4548
0
            oOpenInfo.fpL = VSIFOpenL(
4549
0
                pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4550
0
        }
4551
#else
4552
        if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4553
        {
4554
            CSLDestroy(papszOpenOptionsCleaned);
4555
4556
#ifdef OGRAPISPY_ENABLED
4557
            if (iSnapshot != INT_MIN)
4558
            {
4559
                GDALDatasetH hDS = nullptr;
4560
                OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4561
            }
4562
#endif
4563
            return nullptr;
4564
        }
4565
#endif
4566
0
    }
4567
4568
    // cppcheck-suppress knownConditionTrueFalse
4569
0
    if (iPass == 1 && !apoSecondPassDrivers.empty())
4570
0
    {
4571
0
        CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4572
0
        iPass = 2;
4573
0
        goto retry;
4574
0
    }
4575
4576
0
    CSLDestroy(papszOpenOptionsCleaned);
4577
4578
0
#ifdef OGRAPISPY_ENABLED
4579
0
    if (iSnapshot != INT_MIN)
4580
0
    {
4581
0
        GDALDatasetH hDS = nullptr;
4582
0
        OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4583
0
    }
4584
0
#endif
4585
4586
0
    if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4587
0
    {
4588
0
        std::string osHint;
4589
0
        const CPLStringList aosVSIFSPrefixes(VSIFileManager::GetPrefixes());
4590
0
        for (const char *pszFSPrefix : aosVSIFSPrefixes)
4591
0
        {
4592
0
            auto poFS = VSIFileManager::GetHandler(pszFSPrefix);
4593
0
            if (poFS)
4594
0
            {
4595
0
                osHint = poFS->GetHintForPotentiallyRecognizedPath(pszFilename);
4596
0
                if (!osHint.empty())
4597
0
                {
4598
0
                    osHint = " Changing the filename to " + osHint +
4599
0
                             " may help it to be recognized.";
4600
0
                    break;
4601
0
                }
4602
0
            }
4603
0
        }
4604
4605
0
        if (nDriverCount == 0)
4606
0
        {
4607
0
            CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4608
0
        }
4609
0
        else if (poMissingPluginDriver)
4610
0
        {
4611
0
            std::string osMsg("`");
4612
0
            osMsg += pszFilename;
4613
0
            osMsg += "' not recognized as being in a supported file format. "
4614
0
                     "It could have been recognized by driver ";
4615
0
            osMsg += poMissingPluginDriver->GetDescription();
4616
0
            osMsg += ", but plugin ";
4617
0
            osMsg +=
4618
0
                GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4619
4620
0
            CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4621
0
        }
4622
        // Check to see if there was a filesystem error, and report it if so.
4623
        // If not, return a more generic error.
4624
0
        else if (!osHint.empty() && VSIGetLastErrorNo() == VSIE_FileError)
4625
0
        {
4626
0
            CPLError(CE_Failure, CPLE_FileIO, "%s.%s", VSIGetLastErrorMsg(),
4627
0
                     osHint.c_str());
4628
0
        }
4629
0
        else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4630
0
        {
4631
0
            if (oOpenInfo.bStatOK)
4632
0
            {
4633
0
                CPLError(CE_Failure, CPLE_OpenFailed,
4634
0
                         "`%s' not recognized as being in a supported file "
4635
0
                         "format.%s",
4636
0
                         pszFilename, osHint.c_str());
4637
0
            }
4638
0
            else
4639
0
            {
4640
                // If Stat failed and no VSI error was set, assume it is because
4641
                // the file did not exist on the filesystem.
4642
0
                CPLError(CE_Failure, CPLE_OpenFailed,
4643
0
                         "`%s' does not exist in the file system, "
4644
0
                         "and is not recognized as a supported dataset name.%s",
4645
0
                         pszFilename, osHint.c_str());
4646
0
            }
4647
0
        }
4648
0
    }
4649
4650
0
    return nullptr;
4651
0
}
4652
4653
/************************************************************************/
4654
/*                           GDALOpenShared()                           */
4655
/************************************************************************/
4656
4657
/**
4658
 * \brief Open a raster file as a GDALDataset.
4659
 *
4660
 * This function works the same as GDALOpen(), but allows the sharing of
4661
 * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4662
 *
4663
 * In particular, GDALOpenShared() will first consult its list of currently
4664
 * open and shared GDALDataset's, and if the GetDescription() name for one
4665
 * exactly matches the pszFilename passed to GDALOpenShared() it will be
4666
 * referenced and returned.
4667
 *
4668
 * If GDALOpenShared() is called on the same
4669
 * pszFilename from two different threads, a different GDALDataset object will
4670
 * be returned as it is not safe to use the same dataset from different threads,
4671
 * unless the user does explicitly use mutexes in its code.
4672
 *
4673
 * For drivers supporting the VSI virtual file API, it is possible to open a
4674
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4675
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4676
 * server (see VSIInstallCurlFileHandler())
4677
 *
4678
 * \sa GDALOpen()
4679
 * \sa GDALOpenEx()
4680
 *
4681
 * @param pszFilename the name of the file to access.  In the case of
4682
 * exotic drivers this may not refer to a physical file, but instead contain
4683
 * information for the driver on how to access a dataset.  It should be in
4684
 * UTF-8 encoding.
4685
 *
4686
 * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
4687
 * drivers support only read only access.
4688
 *
4689
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
4690
 * this handle can be cast to a GDALDataset *.
4691
 */
4692
4693
GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4694
                                        GDALAccess eAccess)
4695
0
{
4696
0
    VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4697
0
    return GDALOpenEx(pszFilename,
4698
0
                      GDAL_OF_RASTER |
4699
0
                          (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4700
0
                          GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4701
0
                      nullptr, nullptr, nullptr);
4702
0
}
4703
4704
/************************************************************************/
4705
/*                             GDALClose()                              */
4706
/************************************************************************/
4707
4708
/**
4709
 * \brief Close GDAL dataset.
4710
 *
4711
 * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4712
 * using the C++ "delete" operator, recovering all dataset related resources.
4713
 * For shared datasets (opened with GDALOpenShared()) the dataset is
4714
 * dereferenced, and closed only if the referenced count has dropped below 1.
4715
 *
4716
 * @param hDS The dataset to close, or nullptr.
4717
 * @return CE_None in case of success (return value since GDAL 3.7). On a
4718
 * shared dataset whose reference count is not dropped below 1, CE_None will
4719
 * be returned.
4720
 *
4721
 * @see GDALCloseEx()
4722
 */
4723
4724
CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4725
4726
0
{
4727
0
    return GDALCloseEx(hDS, nullptr, nullptr);
4728
0
}
4729
4730
/************************************************************************/
4731
/*                            GDALCloseEx()                             */
4732
/************************************************************************/
4733
4734
/**
4735
 * \brief Close GDAL dataset.
4736
 *
4737
 * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4738
 * using the C++ "delete" operator, recovering all dataset related resources.
4739
 * For shared datasets (opened with GDALOpenShared()) the dataset is
4740
 * dereferenced, and closed only if the referenced count has dropped below 1.
4741
 *
4742
 * This function may report progress if a progress
4743
 * callback if provided in the pfnProgress argument and if the dataset returns
4744
 * true for GDALDataset::GetCloseReportsProgress()
4745
4746
 * @param hDS The dataset to close, or nullptr
4747
 * @param pfnProgress Progress callback, or nullptr
4748
 * @param pProgressData User data of progress callback, or nullptr
4749
 *
4750
 * @return CE_None in case of success. On a
4751
 * shared dataset whose reference count is not dropped below 1, CE_None will
4752
 * be returned.
4753
 *
4754
 * @since GDAL 3.13
4755
 * @see GDALClose()
4756
 */
4757
4758
CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4759
                   void *pProgressData)
4760
0
{
4761
0
    if (!hDS)
4762
0
        return CE_None;
4763
4764
0
#ifdef OGRAPISPY_ENABLED
4765
0
    if (bOGRAPISpyEnabled)
4766
0
        OGRAPISpyPreClose(hDS);
4767
0
#endif
4768
4769
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4770
4771
0
    if (poDS->GetShared())
4772
0
    {
4773
        /* --------------------------------------------------------------------
4774
         */
4775
        /*      If this file is in the shared dataset list then dereference */
4776
        /*      it, and only delete/remote it if the reference count has */
4777
        /*      dropped to zero. */
4778
        /* --------------------------------------------------------------------
4779
         */
4780
0
        if (poDS->Dereference() > 0)
4781
0
            return CE_None;
4782
0
    }
4783
4784
0
    CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4785
0
    delete poDS;
4786
4787
0
#ifdef OGRAPISPY_ENABLED
4788
0
    if (bOGRAPISpyEnabled)
4789
0
        OGRAPISpyPostClose();
4790
0
#endif
4791
0
    return eErr;
4792
0
}
4793
4794
/************************************************************************/
4795
/*                        GDALDumpOpenDataset()                         */
4796
/************************************************************************/
4797
4798
static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4799
0
{
4800
0
    SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4801
0
    FILE *fp = static_cast<FILE *>(user_data);
4802
0
    GDALDataset *poDS = psStruct->poDS;
4803
4804
0
    const char *pszDriverName = poDS->GetDriver() == nullptr
4805
0
                                    ? "DriverIsNULL"
4806
0
                                    : poDS->GetDriver()->GetDescription();
4807
4808
0
    poDS->Reference();
4809
0
    CPL_IGNORE_RET_VAL(
4810
0
        VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4811
0
                   poDS->GetShared() ? 'S' : 'N', pszDriverName,
4812
0
                   static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4813
0
                   poDS->GetRasterYSize(), poDS->GetRasterCount(),
4814
0
                   poDS->GetDescription()));
4815
4816
0
    return TRUE;
4817
0
}
4818
4819
static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4820
0
{
4821
4822
    // Don't list shared datasets. They have already been listed by
4823
    // GDALDumpOpenSharedDatasetsForeach.
4824
0
    if (poDS->GetShared())
4825
0
        return TRUE;
4826
4827
0
    const char *pszDriverName = poDS->GetDriver() == nullptr
4828
0
                                    ? "DriverIsNULL"
4829
0
                                    : poDS->GetDriver()->GetDescription();
4830
4831
0
    poDS->Reference();
4832
0
    CPL_IGNORE_RET_VAL(
4833
0
        VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4834
0
                   poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4835
0
                   poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4836
0
                   poDS->GetRasterCount(), poDS->GetDescription()));
4837
4838
0
    return TRUE;
4839
0
}
4840
4841
/**
4842
 * \brief List open datasets.
4843
 *
4844
 * Dumps a list of all open datasets (shared or not) to the indicated
4845
 * text file (may be stdout or stderr).   This function is primarily intended
4846
 * to assist in debugging "dataset leaks" and reference counting issues.
4847
 * The information reported includes the dataset name, referenced count,
4848
 * shared status, driver name, size, and band count.
4849
 */
4850
4851
int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4852
4853
0
{
4854
0
    VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4855
4856
0
    CPLMutexHolderD(&hDLMutex);
4857
4858
0
    if (poAllDatasetMap == nullptr)
4859
0
        return 0;
4860
4861
0
    CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4862
4863
0
    for (const auto &oIter : *poAllDatasetMap)
4864
0
    {
4865
0
        GDALDumpOpenDatasetsForeach(oIter.first, fp);
4866
0
    }
4867
4868
0
    if (phSharedDatasetSet != nullptr)
4869
0
    {
4870
0
        CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4871
0
                          fp);
4872
0
    }
4873
0
    return static_cast<int>(poAllDatasetMap->size());
4874
0
}
4875
4876
/************************************************************************/
4877
/*                          BeginAsyncReader()                          */
4878
/************************************************************************/
4879
4880
/**
4881
 * \brief Sets up an asynchronous data request
4882
 *
4883
 * This method establish an asynchronous raster read request for the
4884
 * indicated window on the dataset into the indicated buffer.  The parameters
4885
 * for windowing, buffer size, buffer type and buffer organization are similar
4886
 * to those for GDALDataset::RasterIO(); however, this call only launches
4887
 * the request and filling the buffer is accomplished via calls to
4888
 * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4889
 *
4890
 * Once all processing for the created session is complete, or if no further
4891
 * refinement of the request is required, the GDALAsyncReader object should
4892
 * be destroyed with the GDALDataset::EndAsyncReader() method.
4893
 *
4894
 * Note that the data buffer (pData) will potentially continue to be
4895
 * updated as long as the session lives, but it is not deallocated when
4896
 * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
4897
 * should be deallocated by the application at that point.
4898
 *
4899
 * Additional information on asynchronous IO in GDAL may be found at:
4900
 *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4901
 *
4902
 * This method is the same as the C GDALBeginAsyncReader() function.
4903
 *
4904
 * @param nXOff The pixel offset to the top left corner of the region
4905
 * of the band to be accessed.  This would be zero to start from the left side.
4906
 *
4907
 * @param nYOff The line offset to the top left corner of the region
4908
 * of the band to be accessed.  This would be zero to start from the top.
4909
 *
4910
 * @param nXSize The width of the region of the band to be accessed in pixels.
4911
 *
4912
 * @param nYSize The height of the region of the band to be accessed in lines.
4913
 *
4914
 * @param pBuf The buffer into which the data should be read. This buffer must
4915
 * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4916
 * It is organized in left to right,top to bottom pixel order.  Spacing is
4917
 * controlled by the nPixelSpace, and nLineSpace parameters.
4918
 *
4919
 * @param nBufXSize the width of the buffer image into which the desired region
4920
 * is to be read, or from which it is to be written.
4921
 *
4922
 * @param nBufYSize the height of the buffer image into which the desired
4923
 * region is to be read, or from which it is to be written.
4924
 *
4925
 * @param eBufType the type of the pixel values in the pData data buffer.  The
4926
 * pixel values will automatically be translated to/from the GDALRasterBand
4927
 * data type as needed.
4928
 *
4929
 * @param nBandCount the number of bands being read or written.
4930
 *
4931
 * @param panBandMap the list of nBandCount band numbers being read/written.
4932
 * Note band numbers are 1 based.   This may be NULL to select the first
4933
 * nBandCount bands.
4934
 *
4935
 * @param nPixelSpace The byte offset from the start of one pixel value in
4936
 * pData to the start of the next pixel value within a scanline.  If defaulted
4937
 * (0) the size of the datatype eBufType is used.
4938
 *
4939
 * @param nLineSpace The byte offset from the start of one scanline in
4940
 * pData to the start of the next.  If defaulted the size of the datatype
4941
 * eBufType * nBufXSize is used.
4942
 *
4943
 * @param nBandSpace the byte offset from the start of one bands data to the
4944
 * start of the next.  If defaulted (zero) the value will be
4945
 * nLineSpace * nBufYSize implying band sequential organization
4946
 * of the data buffer.
4947
 *
4948
 * @param papszOptions Driver specific control options in a string list or NULL.
4949
 * Consult driver documentation for options supported.
4950
 *
4951
 * @return The GDALAsyncReader object representing the request.
4952
 */
4953
4954
GDALAsyncReader *GDALDataset::BeginAsyncReader(
4955
    int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4956
    int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4957
    int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4958
0
{
4959
    // See gdaldefaultasync.cpp
4960
4961
0
    return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4962
0
                                     nBufXSize, nBufYSize, eBufType, nBandCount,
4963
0
                                     panBandMap, nPixelSpace, nLineSpace,
4964
0
                                     nBandSpace, papszOptions);
4965
0
}
4966
4967
/************************************************************************/
4968
/*                        GDALBeginAsyncReader()                        */
4969
/************************************************************************/
4970
4971
/**
4972
 * \brief Sets up an asynchronous data request
4973
 *
4974
 * This method establish an asynchronous raster read request for the
4975
 * indicated window on the dataset into the indicated buffer.  The parameters
4976
 * for windowing, buffer size, buffer type and buffer organization are similar
4977
 * to those for GDALDataset::RasterIO(); however, this call only launches
4978
 * the request and filling the buffer is accomplished via calls to
4979
 * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4980
 *
4981
 * Once all processing for the created session is complete, or if no further
4982
 * refinement of the request is required, the GDALAsyncReader object should
4983
 * be destroyed with the GDALDataset::EndAsyncReader() method.
4984
 *
4985
 * Note that the data buffer (pData) will potentially continue to be
4986
 * updated as long as the session lives, but it is not deallocated when
4987
 * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
4988
 * should be deallocated by the application at that point.
4989
 *
4990
 * Additional information on asynchronous IO in GDAL may be found at:
4991
 *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4992
 *
4993
 * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4994
 *
4995
 * @param hDS handle to the dataset object.
4996
 *
4997
 * @param nXOff The pixel offset to the top left corner of the region
4998
 * of the band to be accessed.  This would be zero to start from the left side.
4999
 *
5000
 * @param nYOff The line offset to the top left corner of the region
5001
 * of the band to be accessed.  This would be zero to start from the top.
5002
 *
5003
 * @param nXSize The width of the region of the band to be accessed in pixels.
5004
 *
5005
 * @param nYSize The height of the region of the band to be accessed in lines.
5006
 *
5007
 * @param pBuf The buffer into which the data should be read. This buffer must
5008
 * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
5009
 * It is organized in left to right,top to bottom pixel order.  Spacing is
5010
 * controlled by the nPixelSpace, and nLineSpace parameters.
5011
 *
5012
 * @param nBufXSize the width of the buffer image into which the desired region
5013
 * is to be read, or from which it is to be written.
5014
 *
5015
 * @param nBufYSize the height of the buffer image into which the desired
5016
 * region is to be read, or from which it is to be written.
5017
 *
5018
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5019
 * pixel values will automatically be translated to/from the GDALRasterBand
5020
 * data type as needed.
5021
 *
5022
 * @param nBandCount the number of bands being read or written.
5023
 *
5024
 * @param panBandMap the list of nBandCount band numbers being read/written.
5025
 * Note band numbers are 1 based.   This may be NULL to select the first
5026
 * nBandCount bands.
5027
 *
5028
 * @param nPixelSpace The byte offset from the start of one pixel value in
5029
 * pData to the start of the next pixel value within a scanline.  If defaulted
5030
 * (0) the size of the datatype eBufType is used.
5031
 *
5032
 * @param nLineSpace The byte offset from the start of one scanline in
5033
 * pData to the start of the next.  If defaulted the size of the datatype
5034
 * eBufType * nBufXSize is used.
5035
 *
5036
 * @param nBandSpace the byte offset from the start of one bands data to the
5037
 * start of the next.  If defaulted (zero) the value will be
5038
 * nLineSpace * nBufYSize implying band sequential organization
5039
 * of the data buffer.
5040
 *
5041
 * @param papszOptions Driver specific control options in a string list or NULL.
5042
 * Consult driver documentation for options supported.
5043
 *
5044
 * @return handle representing the request.
5045
 */
5046
5047
GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5048
    GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5049
    int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5050
    int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5051
    CSLConstList papszOptions)
5052
5053
0
{
5054
0
    VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5055
0
    return static_cast<GDALAsyncReaderH>(
5056
0
        GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5057
0
            nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5058
0
            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5059
0
            const_cast<char **>(papszOptions)));
5060
0
}
5061
5062
/************************************************************************/
5063
/*                           EndAsyncReader()                           */
5064
/************************************************************************/
5065
5066
/**
5067
 * End asynchronous request.
5068
 *
5069
 * This method destroys an asynchronous io request and recovers all
5070
 * resources associated with it.
5071
 *
5072
 * This method is the same as the C function GDALEndAsyncReader().
5073
 *
5074
 * @param poARIO pointer to a GDALAsyncReader
5075
 */
5076
5077
void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5078
0
{
5079
0
    delete poARIO;
5080
0
}
5081
5082
/************************************************************************/
5083
/*                         GDALEndAsyncReader()                         */
5084
/************************************************************************/
5085
5086
/**
5087
 * End asynchronous request.
5088
 *
5089
 * This method destroys an asynchronous io request and recovers all
5090
 * resources associated with it.
5091
 *
5092
 * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5093
 *
5094
 * @param hDS handle to the dataset object.
5095
 * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5096
 */
5097
5098
void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5099
                                    GDALAsyncReaderH hAsyncReaderH)
5100
0
{
5101
0
    VALIDATE_POINTER0(hDS, "GDALDataset");
5102
0
    VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5103
0
    GDALDataset::FromHandle(hDS)->EndAsyncReader(
5104
0
        static_cast<GDALAsyncReader *>(hAsyncReaderH));
5105
0
}
5106
5107
/************************************************************************/
5108
/*                       CloseDependentDatasets()                       */
5109
/************************************************************************/
5110
5111
/**
5112
 * Drop references to any other datasets referenced by this dataset.
5113
 *
5114
 * This method should release any reference to other datasets (e.g. a VRT
5115
 * dataset to its sources), but not close the current dataset itself.
5116
 *
5117
 * If at least, one reference to a dependent dataset has been dropped,
5118
 * this method should return TRUE. Otherwise it *should* return FALSE.
5119
 * (Failure to return the proper value might result in infinite loop)
5120
 *
5121
 * This method can be called several times on a given dataset. After
5122
 * the first time, it should not do anything and return FALSE.
5123
 *
5124
 * The driver implementation may choose to destroy its raster bands,
5125
 * so be careful not to call any method on the raster bands afterwards.
5126
 *
5127
 * Basically the only safe action you can do after calling
5128
 * CloseDependentDatasets() is to call the destructor.
5129
 *
5130
 * Note: the only legitimate caller of CloseDependentDatasets() is
5131
 * GDALDriverManager::~GDALDriverManager()
5132
 *
5133
 * @return TRUE if at least one reference to another dataset has been dropped.
5134
 */
5135
int GDALDataset::CloseDependentDatasets()
5136
0
{
5137
0
    return oOvManager.CloseDependentDatasets();
5138
0
}
5139
5140
/************************************************************************/
5141
/*                            ReportError()                             */
5142
/************************************************************************/
5143
5144
#ifndef DOXYGEN_XML
5145
/**
5146
 * \brief Emits an error related to a dataset.
5147
 *
5148
 * This function is a wrapper for regular CPLError(). The only difference
5149
 * with CPLError() is that it prepends the error message with the dataset
5150
 * name.
5151
 *
5152
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5153
 * @param err_no the error number (CPLE_*) from cpl_error.h.
5154
 * @param fmt a printf() style format string.  Any additional arguments
5155
 * will be treated as arguments to fill in this format in a manner
5156
 * similar to printf().
5157
 *
5158
 */
5159
5160
void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5161
                              const char *fmt, ...) const
5162
0
{
5163
0
    va_list args;
5164
0
    va_start(args, fmt);
5165
0
    ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5166
0
    va_end(args);
5167
0
}
5168
5169
/**
5170
 * \brief Emits an error related to a dataset (static method)
5171
 *
5172
 * This function is a wrapper for regular CPLError(). The only difference
5173
 * with CPLError() is that it prepends the error message with the dataset
5174
 * name.
5175
 *
5176
 * @param pszDSName dataset name.
5177
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5178
 * @param err_no the error number (CPLE_*) from cpl_error.h.
5179
 * @param fmt a printf() style format string.  Any additional arguments
5180
 * will be treated as arguments to fill in this format in a manner
5181
 * similar to printf().
5182
 *
5183
 * @since GDAL 3.2.0
5184
 */
5185
5186
void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5187
                              CPLErrorNum err_no, const char *fmt, ...)
5188
0
{
5189
0
    va_list args;
5190
0
    va_start(args, fmt);
5191
0
    ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5192
0
    va_end(args);
5193
0
}
5194
5195
void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5196
                               CPLErrorNum err_no, const char *fmt,
5197
                               va_list args)
5198
0
{
5199
0
    pszDSName = CPLGetFilename(pszDSName);
5200
0
    if (pszDSName[0] != '\0')
5201
0
    {
5202
0
        CPLError(eErrClass, err_no, "%s",
5203
0
                 std::string(pszDSName)
5204
0
                     .append(": ")
5205
0
                     .append(CPLString().vPrintf(fmt, args))
5206
0
                     .c_str());
5207
0
    }
5208
0
    else
5209
0
    {
5210
0
        CPLErrorV(eErrClass, err_no, fmt, args);
5211
0
    }
5212
0
}
5213
#endif
5214
5215
/************************************************************************/
5216
/*                            GetMetadata()                             */
5217
/************************************************************************/
5218
CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5219
0
{
5220
#ifndef WITHOUT_DERIVED
5221
    if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5222
    {
5223
        oDerivedMetadataList.Clear();
5224
5225
        // First condition: at least one raster band.
5226
        if (GetRasterCount() > 0)
5227
        {
5228
            // Check if there is at least one complex band.
5229
            bool hasAComplexBand = false;
5230
5231
            for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5232
            {
5233
                if (GDALDataTypeIsComplex(
5234
                        GetRasterBand(rasterId)->GetRasterDataType()))
5235
                {
5236
                    hasAComplexBand = true;
5237
                    break;
5238
                }
5239
            }
5240
5241
            unsigned int nbSupportedDerivedDS = 0;
5242
            const DerivedDatasetDescription *poDDSDesc =
5243
                GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5244
5245
            int nNumDataset = 1;
5246
            for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5247
                 ++derivedId)
5248
            {
5249
                if (hasAComplexBand ||
5250
                    CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5251
                        "complex")
5252
                {
5253
                    oDerivedMetadataList.SetNameValue(
5254
                        CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5255
                        CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5256
                                   poDDSDesc[derivedId].pszDatasetName,
5257
                                   GetDescription()));
5258
5259
                    CPLString osDesc(
5260
                        CPLSPrintf("%s from %s",
5261
                                   poDDSDesc[derivedId].pszDatasetDescription,
5262
                                   GetDescription()));
5263
                    oDerivedMetadataList.SetNameValue(
5264
                        CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5265
                        osDesc.c_str());
5266
5267
                    nNumDataset++;
5268
                }
5269
            }
5270
        }
5271
        return oDerivedMetadataList.List();
5272
    }
5273
#endif
5274
5275
0
    return GDALMajorObject::GetMetadata(pszDomain);
5276
0
}
5277
5278
// clang-format off
5279
5280
/**
5281
 * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5282
 * \brief Set metadata.
5283
 *
5284
 * CAUTION: depending on the format, older values of the updated information
5285
 * might still be found in the file in a "ghost" state, even if no longer
5286
 * accessible through the GDAL API. This is for example the case of the GTiff
5287
 * format (this is not a exhaustive list)
5288
 *
5289
 * The C function GDALSetMetadata() does the same thing as this method.
5290
 *
5291
 * @param papszMetadata the metadata in name=value string list format to
5292
 * apply.
5293
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
5294
 * domain.
5295
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5296
 * metadata has been accepted, but is likely not maintained persistently
5297
 * by the underlying object between sessions.
5298
 */
5299
5300
/**
5301
 * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5302
 * \brief Set single metadata item.
5303
 *
5304
 * CAUTION: depending on the format, older values of the updated information
5305
 * might still be found in the file in a "ghost" state, even if no longer
5306
 * accessible through the GDAL API. This is for example the case of the GTiff
5307
 * format (this is not a exhaustive list)
5308
 *
5309
 * The C function GDALSetMetadataItem() does the same thing as this method.
5310
 *
5311
 * @param pszName the key for the metadata item to fetch.
5312
 * @param pszValue the value to assign to the key.
5313
 * @param pszDomain the domain to set within, use NULL for the default domain.
5314
 *
5315
 * @return CE_None on success, or an error code on failure.
5316
 */
5317
5318
// clang-format on
5319
5320
/************************************************************************/
5321
/*                       GetMetadataDomainList()                        */
5322
/************************************************************************/
5323
5324
char **GDALDataset::GetMetadataDomainList()
5325
0
{
5326
0
    char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5327
5328
    // Ensure that we do not duplicate DERIVED domain.
5329
0
    if (GetRasterCount() > 0 &&
5330
0
        CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5331
0
    {
5332
0
        currentDomainList =
5333
0
            CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5334
0
    }
5335
0
    return currentDomainList;
5336
0
}
5337
5338
/************************************************************************/
5339
/*                           GetDriverName()                            */
5340
/************************************************************************/
5341
5342
/** Return driver name.
5343
 * @return driver name.
5344
 */
5345
const char *GDALDataset::GetDriverName() const
5346
0
{
5347
0
    if (poDriver)
5348
0
        return poDriver->GetDescription();
5349
0
    return "";
5350
0
}
5351
5352
/************************************************************************/
5353
/*                    GDALDatasetReleaseResultSet()                     */
5354
/************************************************************************/
5355
5356
/**
5357
 \brief Release results of ExecuteSQL().
5358
5359
 This function should only be used to deallocate OGRLayers resulting from
5360
 an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
5361
 results set before destroying the GDALDataset may cause errors.
5362
5363
 This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5364
5365
5366
 @param hDS the dataset handle.
5367
 @param hLayer the result of a previous ExecuteSQL() call.
5368
5369
*/
5370
void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5371
5372
0
{
5373
0
    VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5374
5375
0
#ifdef OGRAPISPY_ENABLED
5376
0
    if (bOGRAPISpyEnabled)
5377
0
        OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5378
0
#endif
5379
5380
0
    GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5381
0
        OGRLayer::FromHandle(hLayer));
5382
0
}
5383
5384
/************************************************************************/
5385
/*                      GDALDatasetGetLayerCount()                      */
5386
/************************************************************************/
5387
5388
/**
5389
 \brief Get the number of layers in this dataset.
5390
5391
 This function is the same as the C++ method GDALDataset::GetLayerCount()
5392
5393
5394
 @param hDS the dataset handle.
5395
 @return layer count.
5396
*/
5397
5398
int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5399
5400
0
{
5401
0
    VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5402
5403
0
#ifdef OGRAPISPY_ENABLED
5404
0
    if (bOGRAPISpyEnabled)
5405
0
        OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5406
0
#endif
5407
5408
0
    return GDALDataset::FromHandle(hDS)->GetLayerCount();
5409
0
}
5410
5411
/************************************************************************/
5412
/*                        GDALDatasetGetLayer()                         */
5413
/************************************************************************/
5414
5415
/**
5416
 \brief Fetch a layer by index.
5417
5418
 The returned layer remains owned by the
5419
 GDALDataset and should not be deleted by the application.
5420
5421
 This function is the same as the C++ method GDALDataset::GetLayer()
5422
5423
5424
 @param hDS the dataset handle.
5425
 @param iLayer a layer number between 0 and GetLayerCount()-1.
5426
5427
 @return the layer, or NULL if iLayer is out of range or an error occurs.
5428
*/
5429
5430
OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5431
5432
0
{
5433
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5434
5435
0
    OGRLayerH hLayer =
5436
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5437
5438
0
#ifdef OGRAPISPY_ENABLED
5439
0
    if (bOGRAPISpyEnabled)
5440
0
        OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5441
0
#endif
5442
5443
0
    return hLayer;
5444
0
}
5445
5446
/************************************************************************/
5447
/*                     GDALDatasetGetLayerByName()                      */
5448
/************************************************************************/
5449
5450
/**
5451
 \brief Fetch a layer by name.
5452
5453
 The returned layer remains owned by the
5454
 GDALDataset and should not be deleted by the application.
5455
5456
 This function is the same as the C++ method GDALDataset::GetLayerByName()
5457
5458
5459
 @param hDS the dataset handle.
5460
 @param pszName the layer name of the layer to fetch.
5461
5462
 @return the layer, or NULL if Layer is not found or an error occurs.
5463
*/
5464
5465
OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5466
5467
0
{
5468
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5469
5470
0
    OGRLayerH hLayer = OGRLayer::ToHandle(
5471
0
        GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5472
5473
0
#ifdef OGRAPISPY_ENABLED
5474
0
    if (bOGRAPISpyEnabled)
5475
0
        OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5476
0
#endif
5477
5478
0
    return hLayer;
5479
0
}
5480
5481
/************************************************************************/
5482
/*                     GDALDatasetIsLayerPrivate()                      */
5483
/************************************************************************/
5484
5485
/**
5486
 \brief Returns true if the layer at the specified index is deemed a private or
5487
 system table, or an internal detail only.
5488
5489
 This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5490
5491
 @since GDAL 3.4
5492
5493
 @param hDS the dataset handle.
5494
 @param iLayer a layer number between 0 and GetLayerCount()-1.
5495
5496
 @return true if the layer is a private or system table.
5497
*/
5498
5499
int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5500
5501
0
{
5502
0
    VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5503
5504
0
    const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5505
5506
0
    return res ? 1 : 0;
5507
0
}
5508
5509
/************************************************************************/
5510
/*                           GetLayerIndex()                            */
5511
/************************************************************************/
5512
5513
/**
5514
 \brief Returns the index of the layer specified by name.
5515
5516
 @since GDAL 3.12
5517
5518
 @param pszName layer name (not NULL)
5519
5520
 @return an index >= 0, or -1 if not found.
5521
*/
5522
5523
int GDALDataset::GetLayerIndex(const char *pszName) const
5524
0
{
5525
0
    const int nLayerCount = GetLayerCount();
5526
0
    int iMatch = -1;
5527
0
    for (int i = 0; i < nLayerCount; ++i)
5528
0
    {
5529
0
        if (const auto poLayer = GetLayer(i))
5530
0
        {
5531
0
            const char *pszLayerName = poLayer->GetDescription();
5532
0
            if (strcmp(pszName, pszLayerName) == 0)
5533
0
            {
5534
0
                iMatch = i;
5535
0
                break;
5536
0
            }
5537
0
            else if (EQUAL(pszName, pszLayerName))
5538
0
            {
5539
0
                iMatch = i;
5540
0
            }
5541
0
        }
5542
0
    }
5543
0
    return iMatch;
5544
0
}
5545
5546
/************************************************************************/
5547
/*                       GDALDatasetDeleteLayer()                       */
5548
/************************************************************************/
5549
5550
/**
5551
 \brief Delete the indicated layer from the datasource.
5552
5553
 If this function is supported
5554
 the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5555
5556
 This method is the same as the C++ method GDALDataset::DeleteLayer().
5557
5558
5559
 @param hDS the dataset handle.
5560
 @param iLayer the index of the layer to delete.
5561
5562
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5563
 layers is not supported for this datasource.
5564
5565
*/
5566
OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5567
5568
0
{
5569
0
    VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5570
5571
0
#ifdef OGRAPISPY_ENABLED
5572
0
    if (bOGRAPISpyEnabled)
5573
0
        OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5574
0
#endif
5575
5576
0
    return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5577
0
}
5578
5579
/************************************************************************/
5580
/*                            CreateLayer()                             */
5581
/************************************************************************/
5582
5583
/**
5584
\brief This method attempts to create a new layer on the dataset with the
5585
indicated name, coordinate system, geometry type.
5586
5587
The papszOptions argument
5588
can be used to control driver specific creation options.  These options are
5589
normally documented in the format specific documentation.
5590
That function will try to validate the creation option list passed to the
5591
driver with the GDALValidateCreationOptions() method. This check can be
5592
disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5593
to NO.
5594
5595
Drivers should extend the ICreateLayer() method and not
5596
CreateLayer(). CreateLayer() adds validation of layer creation options, before
5597
delegating the actual work to ICreateLayer().
5598
5599
This method is the same as the C function GDALDatasetCreateLayer() and the
5600
deprecated OGR_DS_CreateLayer().
5601
5602
Example:
5603
5604
\code{.cpp}
5605
#include "gdal.h"
5606
#include "cpl_string.h"
5607
5608
...
5609
5610
        OGRLayer *poLayer;
5611
        char     **papszOptions;
5612
5613
        if( !poDS->TestCapability( ODsCCreateLayer ) )
5614
        {
5615
        ...
5616
        }
5617
5618
        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5619
        poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5620
                                     papszOptions );
5621
        CSLDestroy( papszOptions );
5622
5623
        if( poLayer == NULL )
5624
        {
5625
            ...
5626
        }
5627
\endcode
5628
5629
@param pszName the name for the new layer.  This should ideally not
5630
match any existing layer on the datasource.
5631
@param poSpatialRef the coordinate system to use for the new layer, or NULL if
5632
no coordinate system is available.
5633
@param eGType the geometry type for the layer.  Use wkbUnknown if there
5634
are no constraints on the types geometry to be written.
5635
@param papszOptions a StringList of name=value options.  Options are driver
5636
specific.
5637
5638
@return NULL is returned on failure, or a new OGRLayer handle on success.
5639
5640
*/
5641
5642
OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5643
                                   const OGRSpatialReference *poSpatialRef,
5644
                                   OGRwkbGeometryType eGType,
5645
                                   CSLConstList papszOptions)
5646
5647
0
{
5648
0
    if (eGType == wkbNone)
5649
0
    {
5650
0
        return CreateLayer(pszName, nullptr, papszOptions);
5651
0
    }
5652
0
    else
5653
0
    {
5654
0
        OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5655
0
        oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5656
0
        return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5657
0
    }
5658
0
}
5659
5660
/**
5661
\brief This method attempts to create a new layer on the dataset with the
5662
indicated name and geometry field definition.
5663
5664
When poGeomFieldDefn is not null, most drivers should honor
5665
poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5666
Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5667
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5668
poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5669
very few currently.
5670
5671
Note that even if a geometry coordinate precision is set and a driver honors the
5672
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5673
OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5674
with the coordinate precision. That is they are assumed to be valid once their
5675
coordinates are rounded to it. If it might not be the case, the user may set
5676
the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5677
or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5678
the passed geometries.
5679
5680
The papszOptions argument
5681
can be used to control driver specific creation options. These options are
5682
normally documented in the format specific documentation.
5683
This function will try to validate the creation option list passed to the
5684
driver with the GDALValidateCreationOptions() method. This check can be
5685
disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5686
to NO.
5687
5688
Drivers should extend the ICreateLayer() method and not
5689
CreateLayer(). CreateLayer() adds validation of layer creation options, before
5690
delegating the actual work to ICreateLayer().
5691
5692
This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5693
5694
@param pszName the name for the new layer.  This should ideally not
5695
match any existing layer on the datasource.
5696
@param poGeomFieldDefn the geometry field definition to use for the new layer,
5697
or NULL if there is no geometry field.
5698
@param papszOptions a StringList of name=value options.  Options are driver
5699
specific.
5700
5701
@return NULL is returned on failure, or a new OGRLayer handle on success.
5702
@since 3.9
5703
5704
*/
5705
5706
OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5707
                                   const OGRGeomFieldDefn *poGeomFieldDefn,
5708
                                   CSLConstList papszOptions)
5709
5710
0
{
5711
0
    if (CPLTestBool(
5712
0
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5713
0
    {
5714
0
        ValidateLayerCreationOptions(papszOptions);
5715
0
    }
5716
5717
0
    OGRLayer *poLayer;
5718
0
    if (poGeomFieldDefn)
5719
0
    {
5720
0
        OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5721
0
        if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5722
0
            !TestCapability(ODsCCurveGeometries))
5723
0
        {
5724
0
            oGeomFieldDefn.SetType(
5725
0
                OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5726
0
        }
5727
5728
0
        poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5729
0
    }
5730
0
    else
5731
0
    {
5732
0
        poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5733
0
    }
5734
0
#ifdef DEBUG
5735
0
    if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5736
0
        !poLayer->TestCapability(OLCCurveGeometries))
5737
0
    {
5738
0
        CPLError(CE_Warning, CPLE_AppDefined,
5739
0
                 "Inconsistent driver: Layer geometry type is non-linear, but "
5740
0
                 "TestCapability(OLCCurveGeometries) returns FALSE.");
5741
0
    }
5742
0
#endif
5743
5744
0
    return poLayer;
5745
0
}
5746
5747
//! @cond Doxygen_Suppress
5748
5749
// Technical override to avoid ambiguous choice between the old and new
5750
// new CreateLayer() signatures.
5751
OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5752
0
{
5753
0
    OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5754
0
    return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5755
0
}
5756
5757
// Technical override to avoid ambiguous choice between the old and new
5758
// new CreateLayer() signatures.
5759
OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5760
0
{
5761
0
    OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5762
0
    return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5763
0
}
5764
5765
//!@endcond
5766
5767
/************************************************************************/
5768
/*                       GDALDatasetCreateLayer()                       */
5769
/************************************************************************/
5770
5771
/**
5772
\brief This function attempts to create a new layer on the dataset with the
5773
indicated name, coordinate system, geometry type.
5774
5775
The papszOptions argument can be used to control driver specific creation
5776
options.  These options are normally documented in the format specific
5777
documentation.
5778
5779
This method is the same as the C++ method GDALDataset::CreateLayer().
5780
5781
Example:
5782
5783
\code{.c}
5784
#include "gdal.h"
5785
#include "cpl_string.h"
5786
5787
...
5788
5789
        OGRLayerH  hLayer;
5790
        char     **papszOptions;
5791
5792
        if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5793
        {
5794
        ...
5795
        }
5796
5797
        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5798
        hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5799
                                         papszOptions );
5800
        CSLDestroy( papszOptions );
5801
5802
        if( hLayer == NULL )
5803
        {
5804
            ...
5805
        }
5806
\endcode
5807
5808
5809
@param hDS the dataset handle
5810
@param pszName the name for the new layer.  This should ideally not
5811
match any existing layer on the datasource.
5812
@param hSpatialRef the coordinate system to use for the new layer, or NULL if
5813
no coordinate system is available.
5814
@param eGType the geometry type for the layer.  Use wkbUnknown if there
5815
are no constraints on the types geometry to be written.
5816
@param papszOptions a StringList of name=value options.  Options are driver
5817
specific.
5818
5819
@return NULL is returned on failure, or a new OGRLayer handle on success.
5820
5821
*/
5822
5823
OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5824
                                 OGRSpatialReferenceH hSpatialRef,
5825
                                 OGRwkbGeometryType eGType,
5826
                                 CSLConstList papszOptions)
5827
5828
0
{
5829
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5830
5831
0
    if (pszName == nullptr)
5832
0
    {
5833
0
        CPLError(CE_Failure, CPLE_ObjectNull,
5834
0
                 "Name was NULL in GDALDatasetCreateLayer");
5835
0
        return nullptr;
5836
0
    }
5837
5838
0
    OGRLayerH hLayer =
5839
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5840
0
            pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5841
0
            const_cast<char **>(papszOptions)));
5842
5843
0
#ifdef OGRAPISPY_ENABLED
5844
0
    if (bOGRAPISpyEnabled)
5845
0
        OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5846
0
                                 const_cast<char **>(papszOptions), hLayer);
5847
0
#endif
5848
5849
0
    return hLayer;
5850
0
}
5851
5852
/************************************************************************/
5853
/*              GDALDatasetCreateLayerFromGeomFieldDefn()               */
5854
/************************************************************************/
5855
5856
/**
5857
\brief This function attempts to create a new layer on the dataset with the
5858
indicated name and geometry field.
5859
5860
When poGeomFieldDefn is not null, most drivers should honor
5861
poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5862
Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5863
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5864
poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5865
very few currently.
5866
5867
Note that even if a geometry coordinate precision is set and a driver honors the
5868
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5869
OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5870
with the coordinate precision. That is they are assumed to be valid once their
5871
coordinates are rounded to it. If it might not be the case, the user may set
5872
the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5873
or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5874
the passed geometries.
5875
5876
The papszOptions argument can be used to control driver specific creation
5877
options.  These options are normally documented in the format specific
5878
documentation.
5879
5880
This method is the same as the C++ method GDALDataset::CreateLayer().
5881
5882
@param hDS the dataset handle
5883
@param pszName the name for the new layer.  This should ideally not
5884
match any existing layer on the datasource.
5885
@param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5886
a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5887
for drivers supporting that interface).
5888
@param papszOptions a StringList of name=value options.  Options are driver
5889
specific.
5890
5891
@return NULL is returned on failure, or a new OGRLayer handle on success.
5892
5893
@since GDAL 3.9
5894
5895
*/
5896
5897
OGRLayerH
5898
GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5899
                                        OGRGeomFieldDefnH hGeomFieldDefn,
5900
                                        CSLConstList papszOptions)
5901
5902
0
{
5903
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5904
5905
0
    if (!pszName)
5906
0
    {
5907
0
        CPLError(CE_Failure, CPLE_ObjectNull,
5908
0
                 "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5909
0
        return nullptr;
5910
0
    }
5911
5912
0
    OGRLayerH hLayer =
5913
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5914
0
            pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5915
0
            papszOptions));
5916
0
    return hLayer;
5917
0
}
5918
5919
/************************************************************************/
5920
/*                        GDALDatasetCopyLayer()                        */
5921
/************************************************************************/
5922
5923
/**
5924
 \brief Duplicate an existing layer.
5925
5926
 This function creates a new layer, duplicate the field definitions of the
5927
 source layer and then duplicate each features of the source layer.
5928
 The papszOptions argument
5929
 can be used to control driver specific creation options.  These options are
5930
 normally documented in the format specific documentation.
5931
 The source layer may come from another dataset.
5932
5933
 This method is the same as the C++ method GDALDataset::CopyLayer()
5934
5935
5936
 @param hDS the dataset handle.
5937
 @param hSrcLayer source layer.
5938
 @param pszNewName the name of the layer to create.
5939
 @param papszOptions a StringList of name=value options.  Options are driver
5940
                     specific.
5941
5942
 @return a handle to the layer, or NULL if an error occurs.
5943
*/
5944
OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5945
                               const char *pszNewName,
5946
                               CSLConstList papszOptions)
5947
5948
0
{
5949
0
    VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5950
0
    VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5951
0
    VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5952
5953
0
    return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5954
0
        OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5955
0
}
5956
5957
/************************************************************************/
5958
/*                       GDALDatasetExecuteSQL()                        */
5959
/************************************************************************/
5960
5961
/**
5962
 \brief Execute an SQL statement against the data store.
5963
5964
 The result of an SQL query is either NULL for statements that are in error,
5965
 or that have no results set, or an OGRLayer pointer representing a results
5966
 set from the query.  Note that this OGRLayer is in addition to the layers
5967
 in the data store and must be destroyed with
5968
 ReleaseResultSet() before the dataset is closed
5969
 (destroyed).
5970
5971
 This method is the same as the C++ method GDALDataset::ExecuteSQL()
5972
5973
 For more information on the SQL dialect supported internally by OGR
5974
 review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5975
 document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5976
 to the underlying RDBMS.
5977
5978
 Starting with OGR 1.10, the <a
5979
 href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5980
 also be used.
5981
5982
5983
 @param hDS the dataset handle.
5984
 @param pszStatement the SQL statement to execute.
5985
 @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5986
5987
 @param pszDialect allows control of the statement dialect. If set to NULL, the
5988
 OGR SQL engine will be used, except for RDBMS drivers that will use their
5989
 dedicated SQL engine, unless OGRSQL is explicitly passed as the
5990
 dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5991
5992
 @return an OGRLayer containing the results of the query.  Deallocate with
5993
 GDALDatasetReleaseResultSet().
5994
5995
*/
5996
5997
OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5998
                                OGRGeometryH hSpatialFilter,
5999
                                const char *pszDialect)
6000
6001
0
{
6002
0
    VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
6003
6004
0
    OGRLayerH hLayer =
6005
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
6006
0
            pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
6007
6008
0
#ifdef OGRAPISPY_ENABLED
6009
0
    if (bOGRAPISpyEnabled)
6010
0
        OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
6011
0
                                hLayer);
6012
0
#endif
6013
6014
0
    return hLayer;
6015
0
}
6016
6017
/************************************************************************/
6018
/*                        GDALDatasetAbortSQL()                         */
6019
/************************************************************************/
6020
6021
/**
6022
 \brief Abort any SQL statement running in the data store.
6023
6024
 This function can be safely called from any thread (pending that the dataset
6025
 object is still alive). Driver implementations will make sure that it can be
6026
 called in a thread-safe way.
6027
6028
 This might not be implemented by all drivers. At time of writing, only SQLite,
6029
 GPKG and PG drivers implement it
6030
6031
 This method is the same as the C++ method GDALDataset::AbortSQL()
6032
6033
 @since GDAL 3.2.0
6034
6035
 @param hDS the dataset handle.
6036
6037
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6038
 is not supported for this datasource. .
6039
6040
*/
6041
6042
OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6043
6044
0
{
6045
0
    VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6046
0
    return GDALDataset::FromHandle(hDS)->AbortSQL();
6047
0
}
6048
6049
/************************************************************************/
6050
/*                      GDALDatasetGetStyleTable()                      */
6051
/************************************************************************/
6052
6053
/**
6054
 \brief Returns dataset style table.
6055
6056
 This function is the same as the C++ method GDALDataset::GetStyleTable()
6057
6058
6059
 @param hDS the dataset handle
6060
 @return handle to a style table which should not be modified or freed by the
6061
 caller.
6062
*/
6063
6064
OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6065
6066
0
{
6067
0
    VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6068
6069
0
    return reinterpret_cast<OGRStyleTableH>(
6070
0
        GDALDataset::FromHandle(hDS)->GetStyleTable());
6071
0
}
6072
6073
/************************************************************************/
6074
/*                  GDALDatasetSetStyleTableDirectly()                  */
6075
/************************************************************************/
6076
6077
/**
6078
 \brief Set dataset style table.
6079
6080
 This function operate exactly as GDALDatasetSetStyleTable() except that it
6081
 assumes ownership of the passed table.
6082
6083
 This function is the same as the C++ method
6084
 GDALDataset::SetStyleTableDirectly()
6085
6086
6087
 @param hDS the dataset handle
6088
 @param hStyleTable style table handle to set
6089
6090
*/
6091
6092
void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6093
                                      OGRStyleTableH hStyleTable)
6094
6095
0
{
6096
0
    VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6097
6098
0
    GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6099
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
6100
0
}
6101
6102
/************************************************************************/
6103
/*                      GDALDatasetSetStyleTable()                      */
6104
/************************************************************************/
6105
6106
/**
6107
 \brief Set dataset style table.
6108
6109
 This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6110
 it assumes ownership of the passed table.
6111
6112
 This function is the same as the C++ method GDALDataset::SetStyleTable()
6113
6114
6115
 @param hDS the dataset handle
6116
 @param hStyleTable style table handle to set
6117
6118
*/
6119
6120
void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6121
6122
0
{
6123
0
    VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6124
0
    VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6125
6126
0
    GDALDataset::FromHandle(hDS)->SetStyleTable(
6127
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
6128
0
}
6129
6130
/************************************************************************/
6131
/*                    ValidateLayerCreationOptions()                    */
6132
/************************************************************************/
6133
6134
//! @cond Doxygen_Suppress
6135
int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6136
0
{
6137
0
    const char *pszOptionList =
6138
0
        GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6139
0
    if (pszOptionList == nullptr && poDriver != nullptr)
6140
0
    {
6141
0
        pszOptionList =
6142
0
            poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6143
0
    }
6144
0
    CPLString osDataset;
6145
0
    osDataset.Printf("dataset %s", GetDescription());
6146
0
    return GDALValidateOptions(GDALDriver::ToHandle(poDriver), pszOptionList,
6147
0
                               papszLCO, "layer creation option", osDataset);
6148
0
}
6149
6150
//! @endcond
6151
6152
/************************************************************************/
6153
/*                              Release()                               */
6154
/************************************************************************/
6155
6156
/**
6157
\brief Drop a reference to this dataset, and if the reference count drops to one
6158
close (destroy) the dataset.
6159
6160
This method is the same as the C function OGRReleaseDataSource().
6161
6162
@deprecated. Use GDALClose() instead
6163
6164
@return OGRERR_NONE on success or an error code.
6165
*/
6166
6167
OGRErr GDALDataset::Release()
6168
6169
0
{
6170
0
    ReleaseRef();
6171
0
    return OGRERR_NONE;
6172
0
}
6173
6174
/************************************************************************/
6175
/*                            GetRefCount()                             */
6176
/************************************************************************/
6177
6178
/**
6179
\brief Fetch reference count.
6180
6181
This method is the same as the C function OGR_DS_GetRefCount().
6182
6183
@return the current reference count for the datasource object itself.
6184
*/
6185
6186
int GDALDataset::GetRefCount() const
6187
0
{
6188
0
    return nRefCount;
6189
0
}
6190
6191
/************************************************************************/
6192
/*                         GetSummaryRefCount()                         */
6193
/************************************************************************/
6194
6195
/**
6196
\brief Fetch reference count of datasource and all owned layers.
6197
6198
This method is the same as the C function  OGR_DS_GetSummaryRefCount().
6199
6200
@deprecated
6201
6202
@return the current summary reference count for the datasource and its layers.
6203
*/
6204
6205
int GDALDataset::GetSummaryRefCount() const
6206
6207
0
{
6208
0
    CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6209
0
    int nSummaryCount = nRefCount;
6210
0
    GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6211
6212
0
    for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6213
0
        nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6214
6215
0
    return nSummaryCount;
6216
0
}
6217
6218
/************************************************************************/
6219
/*                            ICreateLayer()                            */
6220
/************************************************************************/
6221
6222
/**
6223
 \brief This method attempts to create a new layer on the dataset with the
6224
 indicated name, coordinate system, geometry type.
6225
6226
 This method is reserved to implementation by drivers.
6227
6228
 The papszOptions argument can be used to control driver specific creation
6229
 options.  These options are normally documented in the format specific
6230
 documentation.
6231
6232
 @param pszName the name for the new layer.  This should ideally not
6233
 match any existing layer on the datasource.
6234
 @param poGeomFieldDefn the geometry field definition to use for the new layer,
6235
 or NULL if there is no geometry field.
6236
 @param papszOptions a StringList of name=value options.  Options are driver
6237
 specific.
6238
6239
 @return NULL is returned on failure, or a new OGRLayer handle on success.
6240
6241
*/
6242
6243
OGRLayer *
6244
GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6245
                          CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6246
                          CPL_UNUSED CSLConstList papszOptions)
6247
6248
0
{
6249
0
    CPLError(CE_Failure, CPLE_NotSupported,
6250
0
             "CreateLayer() not supported by this dataset.");
6251
6252
0
    return nullptr;
6253
0
}
6254
6255
/************************************************************************/
6256
/*                             CopyLayer()                              */
6257
/************************************************************************/
6258
6259
/**
6260
 \brief Duplicate an existing layer.
6261
6262
 This method creates a new layer, duplicate the field definitions of the
6263
 source layer and then duplicate each features of the source layer.
6264
 The papszOptions argument
6265
 can be used to control driver specific creation options.  These options are
6266
 normally documented in the format specific documentation.
6267
 The source layer may come from another dataset.
6268
6269
 This method is the same as the C function GDALDatasetCopyLayer() and the
6270
 deprecated OGR_DS_CopyLayer().
6271
6272
 @param poSrcLayer source layer.
6273
 @param pszNewName the name of the layer to create.
6274
 @param papszOptions a StringList of name=value options.  Options are driver
6275
                     specific. There is a common option to set output layer
6276
                     spatial reference: DST_SRSWKT. The option should be in
6277
                     WKT format. Starting with GDAL 3.7, the common option
6278
                     COPY_MD can be set to NO to prevent the default copying
6279
                     of the metadata from the source layer to the target layer.
6280
6281
 @return a handle to the layer, or NULL if an error occurs.
6282
*/
6283
6284
OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6285
                                 CSLConstList papszOptions)
6286
6287
0
{
6288
    /* -------------------------------------------------------------------- */
6289
    /*      Create the layer.                                               */
6290
    /* -------------------------------------------------------------------- */
6291
0
    if (!TestCapability(ODsCCreateLayer))
6292
0
    {
6293
0
        CPLError(CE_Failure, CPLE_NotSupported,
6294
0
                 "This datasource does not support creation of layers.");
6295
0
        return nullptr;
6296
0
    }
6297
6298
0
    const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6299
0
    OGRSpatialReference oDstSpaRef(pszSRSWKT);
6300
0
    oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6301
0
    OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6302
0
    OGRLayer *poDstLayer = nullptr;
6303
6304
0
    CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6305
0
    aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6306
0
    aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6307
6308
0
    CPLErrorReset();
6309
0
    const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6310
0
    if (nSrcGeomFieldCount == 1)
6311
0
    {
6312
0
        OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6313
0
        if (pszSRSWKT)
6314
0
            oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6315
0
        poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6316
0
                                  aosCleanedUpOptions.List());
6317
0
    }
6318
0
    else
6319
0
    {
6320
0
        poDstLayer =
6321
0
            ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6322
0
    }
6323
6324
0
    if (poDstLayer == nullptr)
6325
0
        return nullptr;
6326
6327
0
    if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6328
0
    {
6329
0
        CSLConstList papszMD = poSrcLayer->GetMetadata();
6330
0
        if (papszMD)
6331
0
            poDstLayer->SetMetadata(papszMD);
6332
0
    }
6333
6334
    /* -------------------------------------------------------------------- */
6335
    /*      Add fields.  Default to copy all fields, and make sure to       */
6336
    /*      establish a mapping between indices, rather than names, in      */
6337
    /*      case the target datasource has altered it (e.g. Shapefile       */
6338
    /*      limited to 10 char field names).                                */
6339
    /* -------------------------------------------------------------------- */
6340
0
    const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6341
6342
    // Initialize the index-to-index map to -1's.
6343
0
    std::vector<int> anMap(nSrcFieldCount, -1);
6344
6345
    // Caution: At the time of writing, the MapInfo driver
6346
    // returns NULL until a field has been added.
6347
0
    OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6348
0
    int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6349
0
    for (int iField = 0; iField < nSrcFieldCount; ++iField)
6350
0
    {
6351
0
        OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6352
0
        OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6353
6354
        // The field may have been already created at layer creation.
6355
0
        int iDstField = -1;
6356
0
        if (poDstFDefn)
6357
0
            iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6358
0
        if (iDstField >= 0)
6359
0
        {
6360
0
            anMap[iField] = iDstField;
6361
0
        }
6362
0
        else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6363
0
        {
6364
            // Now that we've created a field, GetLayerDefn() won't return NULL.
6365
0
            if (poDstFDefn == nullptr)
6366
0
                poDstFDefn = poDstLayer->GetLayerDefn();
6367
6368
            // Sanity check: if it fails, the driver is buggy.
6369
0
            if (poDstFDefn != nullptr &&
6370
0
                poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6371
0
            {
6372
0
                CPLError(CE_Warning, CPLE_AppDefined,
6373
0
                         "The output driver has claimed to have added the %s "
6374
0
                         "field, but it did not!",
6375
0
                         oFieldDefn.GetNameRef());
6376
0
            }
6377
0
            else
6378
0
            {
6379
0
                anMap[iField] = nDstFieldCount;
6380
0
                ++nDstFieldCount;
6381
0
            }
6382
0
        }
6383
0
    }
6384
6385
    /* -------------------------------------------------------------------- */
6386
0
    std::unique_ptr<OGRCoordinateTransformation> poCT;
6387
0
    const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6388
0
    if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6389
0
        sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6390
0
    {
6391
0
        poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6392
0
        if (nullptr == poCT)
6393
0
        {
6394
0
            CPLError(CE_Failure, CPLE_NotSupported,
6395
0
                     "This input/output spatial reference is not supported.");
6396
0
            return nullptr;
6397
0
        }
6398
0
    }
6399
    /* -------------------------------------------------------------------- */
6400
    /*      Create geometry fields.                                         */
6401
    /* -------------------------------------------------------------------- */
6402
0
    if (nSrcGeomFieldCount > 1 &&
6403
0
        TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6404
0
    {
6405
6406
0
        for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6407
0
        {
6408
0
            if (nullptr == pszSRSWKT)
6409
0
            {
6410
0
                poDstLayer->CreateGeomField(
6411
0
                    poSrcDefn->GetGeomFieldDefn(iField));
6412
0
            }
6413
0
            else
6414
0
            {
6415
0
                OGRGeomFieldDefn *pDstGeomFieldDefn =
6416
0
                    poSrcDefn->GetGeomFieldDefn(iField);
6417
0
                pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6418
0
                poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6419
0
            }
6420
0
        }
6421
0
    }
6422
6423
    /* -------------------------------------------------------------------- */
6424
    /*      Check if the destination layer supports transactions and set a  */
6425
    /*      default number of features in a single transaction.             */
6426
    /* -------------------------------------------------------------------- */
6427
0
    const int nGroupTransactions =
6428
0
        poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6429
6430
    /* -------------------------------------------------------------------- */
6431
    /*      Transfer features.                                              */
6432
    /* -------------------------------------------------------------------- */
6433
0
    poSrcLayer->ResetReading();
6434
6435
0
    if (nGroupTransactions <= 0)
6436
0
    {
6437
0
        while (true)
6438
0
        {
6439
0
            auto poFeature =
6440
0
                std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6441
6442
0
            if (poFeature == nullptr)
6443
0
                break;
6444
6445
0
            CPLErrorReset();
6446
0
            auto poDstFeature =
6447
0
                std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6448
6449
0
            if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6450
0
                OGRERR_NONE)
6451
0
            {
6452
0
                CPLError(CE_Failure, CPLE_AppDefined,
6453
0
                         "Unable to translate feature " CPL_FRMT_GIB
6454
0
                         " from layer %s.",
6455
0
                         poFeature->GetFID(), poSrcDefn->GetName());
6456
0
                return poDstLayer;
6457
0
            }
6458
6459
0
            if (nullptr != poCT)
6460
0
            {
6461
0
                for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6462
0
                {
6463
0
                    OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6464
0
                    if (nullptr == pGeom)
6465
0
                        continue;
6466
6467
0
                    const OGRErr eErr = pGeom->transform(poCT.get());
6468
0
                    if (eErr == OGRERR_NONE)
6469
0
                        continue;
6470
6471
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6472
0
                             "Unable to transform geometry " CPL_FRMT_GIB
6473
0
                             " from layer %s.",
6474
0
                             poFeature->GetFID(), poSrcDefn->GetName());
6475
0
                    return poDstLayer;
6476
0
                }
6477
0
            }
6478
6479
0
            poDstFeature->SetFID(poFeature->GetFID());
6480
6481
0
            CPLErrorReset();
6482
0
            if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6483
0
            {
6484
0
                return poDstLayer;
6485
0
            }
6486
0
        }
6487
0
    }
6488
0
    else
6489
0
    {
6490
0
        std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6491
0
        try
6492
0
        {
6493
0
            apoDstFeatures.resize(nGroupTransactions);
6494
0
        }
6495
0
        catch (const std::exception &e)
6496
0
        {
6497
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6498
0
            return poDstLayer;
6499
0
        }
6500
0
        bool bStopTransfer = false;
6501
0
        while (!bStopTransfer)
6502
0
        {
6503
            /* --------------------------------------------------------------------
6504
             */
6505
            /*      Fill the array with features. */
6506
            /* --------------------------------------------------------------------
6507
             */
6508
            // Number of features in the temporary array.
6509
0
            int nFeatCount = 0;  // Used after for.
6510
0
            for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6511
0
            {
6512
0
                auto poFeature =
6513
0
                    std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6514
6515
0
                if (poFeature == nullptr)
6516
0
                {
6517
0
                    bStopTransfer = true;
6518
0
                    break;
6519
0
                }
6520
6521
0
                CPLErrorReset();
6522
0
                apoDstFeatures[nFeatCount] =
6523
0
                    std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6524
6525
0
                if (apoDstFeatures[nFeatCount]->SetFrom(
6526
0
                        poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6527
0
                {
6528
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6529
0
                             "Unable to translate feature " CPL_FRMT_GIB
6530
0
                             " from layer %s.",
6531
0
                             poFeature->GetFID(), poSrcDefn->GetName());
6532
0
                    bStopTransfer = true;
6533
0
                    poFeature.reset();
6534
0
                    break;
6535
0
                }
6536
6537
0
                if (nullptr != poCT)
6538
0
                {
6539
0
                    for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6540
0
                    {
6541
0
                        OGRGeometry *pGeom =
6542
0
                            apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6543
0
                        if (nullptr == pGeom)
6544
0
                            continue;
6545
6546
0
                        const OGRErr eErr = pGeom->transform(poCT.get());
6547
0
                        if (eErr == OGRERR_NONE)
6548
0
                            continue;
6549
6550
0
                        CPLError(CE_Failure, CPLE_AppDefined,
6551
0
                                 "Unable to transform geometry " CPL_FRMT_GIB
6552
0
                                 " from layer %s.",
6553
0
                                 poFeature->GetFID(), poSrcDefn->GetName());
6554
0
                        bStopTransfer = true;
6555
0
                        poFeature.reset();
6556
0
                        break;
6557
0
                    }
6558
0
                }
6559
6560
0
                if (poFeature)
6561
0
                {
6562
0
                    apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6563
0
                }
6564
0
            }
6565
6566
0
            CPLErrorReset();
6567
0
            bool bStopTransaction = false;
6568
0
            while (!bStopTransaction)
6569
0
            {
6570
0
                bStopTransaction = true;
6571
0
                if (poDstLayer->StartTransaction() != OGRERR_NONE)
6572
0
                    break;
6573
0
                for (int i = 0; i < nFeatCount; ++i)
6574
0
                {
6575
0
                    if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6576
0
                        OGRERR_NONE)
6577
0
                    {
6578
0
                        bStopTransfer = true;
6579
0
                        bStopTransaction = false;
6580
0
                        break;
6581
0
                    }
6582
0
                    apoDstFeatures[i].reset();
6583
0
                }
6584
0
                if (bStopTransaction)
6585
0
                {
6586
0
                    if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6587
0
                        break;
6588
0
                }
6589
0
                else
6590
0
                {
6591
0
                    poDstLayer->RollbackTransaction();
6592
0
                }
6593
0
            }
6594
0
        }
6595
0
    }
6596
6597
0
    return poDstLayer;
6598
0
}
6599
6600
/************************************************************************/
6601
/*                            DeleteLayer()                             */
6602
/************************************************************************/
6603
6604
/**
6605
 \fn GDALDataset::DeleteLayer(int)
6606
 \brief Delete the indicated layer from the datasource.
6607
6608
 If this method is supported
6609
 the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6610
6611
 This method is the same as the C function GDALDatasetDeleteLayer() and the
6612
 deprecated OGR_DS_DeleteLayer().
6613
6614
 @param iLayer the index of the layer to delete.
6615
6616
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6617
 layers is not supported for this datasource.
6618
6619
*/
6620
6621
OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6622
6623
0
{
6624
0
    CPLError(CE_Failure, CPLE_NotSupported,
6625
0
             "DeleteLayer() not supported by this dataset.");
6626
6627
0
    return OGRERR_UNSUPPORTED_OPERATION;
6628
0
}
6629
6630
/************************************************************************/
6631
/*                           GetLayerByName()                           */
6632
/************************************************************************/
6633
6634
/**
6635
 \brief Fetch a layer by name.
6636
6637
 The returned layer remains owned by the
6638
 GDALDataset and should not be deleted by the application.
6639
6640
 This method is the same as the C function GDALDatasetGetLayerByName() and the
6641
 deprecated OGR_DS_GetLayerByName().
6642
6643
 @param pszName the layer name of the layer to fetch.
6644
6645
 @return the layer, or NULL if Layer is not found or an error occurs.
6646
*/
6647
6648
OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6649
6650
0
{
6651
0
    CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6652
6653
0
    if (!pszName)
6654
0
        return nullptr;
6655
6656
    // First a case sensitive check.
6657
0
    for (auto *poLayer : GetLayers())
6658
0
    {
6659
0
        if (strcmp(pszName, poLayer->GetName()) == 0)
6660
0
            return poLayer;
6661
0
    }
6662
6663
    // Then case insensitive.
6664
0
    for (auto *poLayer : GetLayers())
6665
0
    {
6666
0
        if (EQUAL(pszName, poLayer->GetName()))
6667
0
            return poLayer;
6668
0
    }
6669
6670
0
    return nullptr;
6671
0
}
6672
6673
//! @cond Doxygen_Suppress
6674
/************************************************************************/
6675
/*                       ProcessSQLCreateIndex()                        */
6676
/*                                                                      */
6677
/*      The correct syntax for creating an index in our dialect of      */
6678
/*      SQL is:                                                         */
6679
/*                                                                      */
6680
/*        CREATE INDEX ON <layername> USING <columnname>                */
6681
/************************************************************************/
6682
6683
OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6684
6685
0
{
6686
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6687
6688
    /* -------------------------------------------------------------------- */
6689
    /*      Do some general syntax checking.                                */
6690
    /* -------------------------------------------------------------------- */
6691
0
    if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6692
0
        !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6693
0
        !EQUAL(papszTokens[4], "USING"))
6694
0
    {
6695
0
        CSLDestroy(papszTokens);
6696
0
        CPLError(CE_Failure, CPLE_AppDefined,
6697
0
                 "Syntax error in CREATE INDEX command.\n"
6698
0
                 "Was '%s'\n"
6699
0
                 "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6700
0
                 pszSQLCommand);
6701
0
        return OGRERR_FAILURE;
6702
0
    }
6703
6704
    /* -------------------------------------------------------------------- */
6705
    /*      Find the named layer.                                           */
6706
    /* -------------------------------------------------------------------- */
6707
0
    OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6708
0
    if (poLayer == nullptr)
6709
0
    {
6710
0
        CPLError(CE_Failure, CPLE_AppDefined,
6711
0
                 "CREATE INDEX ON failed, no such layer as `%s'.",
6712
0
                 papszTokens[3]);
6713
0
        CSLDestroy(papszTokens);
6714
0
        return OGRERR_FAILURE;
6715
0
    }
6716
6717
    /* -------------------------------------------------------------------- */
6718
    /*      Does this layer even support attribute indexes?                 */
6719
    /* -------------------------------------------------------------------- */
6720
0
    if (poLayer->GetIndex() == nullptr)
6721
0
    {
6722
0
        CPLError(CE_Failure, CPLE_AppDefined,
6723
0
                 "CREATE INDEX ON not supported by this driver.");
6724
0
        CSLDestroy(papszTokens);
6725
0
        return OGRERR_FAILURE;
6726
0
    }
6727
6728
    /* -------------------------------------------------------------------- */
6729
    /*      Find the named field.                                           */
6730
    /* -------------------------------------------------------------------- */
6731
0
    int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6732
6733
0
    CSLDestroy(papszTokens);
6734
6735
0
    if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6736
0
    {
6737
0
        CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6738
0
                 pszSQLCommand);
6739
0
        return OGRERR_FAILURE;
6740
0
    }
6741
6742
    /* -------------------------------------------------------------------- */
6743
    /*      Attempt to create the index.                                    */
6744
    /* -------------------------------------------------------------------- */
6745
0
    OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6746
0
    if (eErr == OGRERR_NONE)
6747
0
    {
6748
0
        eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6749
0
    }
6750
0
    else
6751
0
    {
6752
0
        if (strlen(CPLGetLastErrorMsg()) == 0)
6753
0
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6754
0
    }
6755
6756
0
    return eErr;
6757
0
}
6758
6759
/************************************************************************/
6760
/*                        ProcessSQLDropIndex()                         */
6761
/*                                                                      */
6762
/*      The correct syntax for dropping one or more indexes in          */
6763
/*      the OGR SQL dialect is:                                         */
6764
/*                                                                      */
6765
/*          DROP INDEX ON <layername> [USING <columnname>]              */
6766
/************************************************************************/
6767
6768
OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6769
6770
0
{
6771
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6772
6773
    /* -------------------------------------------------------------------- */
6774
    /*      Do some general syntax checking.                                */
6775
    /* -------------------------------------------------------------------- */
6776
0
    if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6777
0
        !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6778
0
        !EQUAL(papszTokens[2], "ON") ||
6779
0
        (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6780
0
    {
6781
0
        CSLDestroy(papszTokens);
6782
0
        CPLError(CE_Failure, CPLE_AppDefined,
6783
0
                 "Syntax error in DROP INDEX command.\n"
6784
0
                 "Was '%s'\n"
6785
0
                 "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6786
0
                 pszSQLCommand);
6787
0
        return OGRERR_FAILURE;
6788
0
    }
6789
6790
    /* -------------------------------------------------------------------- */
6791
    /*      Find the named layer.                                           */
6792
    /* -------------------------------------------------------------------- */
6793
0
    OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6794
0
    if (poLayer == nullptr)
6795
0
    {
6796
0
        CPLError(CE_Failure, CPLE_AppDefined,
6797
0
                 "DROP INDEX ON failed, no such layer as `%s'.",
6798
0
                 papszTokens[3]);
6799
0
        CSLDestroy(papszTokens);
6800
0
        return OGRERR_FAILURE;
6801
0
    }
6802
6803
    /* -------------------------------------------------------------------- */
6804
    /*      Does this layer even support attribute indexes?                 */
6805
    /* -------------------------------------------------------------------- */
6806
0
    if (poLayer->GetIndex() == nullptr)
6807
0
    {
6808
0
        CPLError(CE_Failure, CPLE_AppDefined,
6809
0
                 "Indexes not supported by this driver.");
6810
0
        CSLDestroy(papszTokens);
6811
0
        return OGRERR_FAILURE;
6812
0
    }
6813
6814
    /* -------------------------------------------------------------------- */
6815
    /*      If we were not given a field name, drop all indexes.            */
6816
    /* -------------------------------------------------------------------- */
6817
0
    if (CSLCount(papszTokens) == 4)
6818
0
    {
6819
0
        for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6820
0
        {
6821
0
            OGRAttrIndex *poAttrIndex;
6822
6823
0
            poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6824
0
            if (poAttrIndex != nullptr)
6825
0
            {
6826
0
                const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6827
0
                if (eErr != OGRERR_NONE)
6828
0
                {
6829
0
                    CSLDestroy(papszTokens);
6830
0
                    return eErr;
6831
0
                }
6832
0
            }
6833
0
        }
6834
6835
0
        CSLDestroy(papszTokens);
6836
0
        return OGRERR_NONE;
6837
0
    }
6838
6839
    /* -------------------------------------------------------------------- */
6840
    /*      Find the named field.                                           */
6841
    /* -------------------------------------------------------------------- */
6842
0
    int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6843
0
    CSLDestroy(papszTokens);
6844
6845
0
    if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6846
0
    {
6847
0
        CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6848
0
                 pszSQLCommand);
6849
0
        return OGRERR_FAILURE;
6850
0
    }
6851
6852
    /* -------------------------------------------------------------------- */
6853
    /*      Attempt to drop the index.                                      */
6854
    /* -------------------------------------------------------------------- */
6855
0
    const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6856
6857
0
    return eErr;
6858
0
}
6859
6860
/************************************************************************/
6861
/*                        ProcessSQLDropTable()                         */
6862
/*                                                                      */
6863
/*      The correct syntax for dropping a table (layer) in the OGR SQL  */
6864
/*      dialect is:                                                     */
6865
/*                                                                      */
6866
/*          DROP TABLE <layername>                                      */
6867
/************************************************************************/
6868
6869
OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6870
6871
0
{
6872
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6873
6874
    /* -------------------------------------------------------------------- */
6875
    /*      Do some general syntax checking.                                */
6876
    /* -------------------------------------------------------------------- */
6877
0
    if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6878
0
        !EQUAL(papszTokens[1], "TABLE"))
6879
0
    {
6880
0
        CSLDestroy(papszTokens);
6881
0
        CPLError(CE_Failure, CPLE_AppDefined,
6882
0
                 "Syntax error in DROP TABLE command.\n"
6883
0
                 "Was '%s'\n"
6884
0
                 "Should be of form 'DROP TABLE <table>'",
6885
0
                 pszSQLCommand);
6886
0
        return OGRERR_FAILURE;
6887
0
    }
6888
6889
    /* -------------------------------------------------------------------- */
6890
    /*      Find the named layer.                                           */
6891
    /* -------------------------------------------------------------------- */
6892
0
    OGRLayer *poLayer = nullptr;
6893
6894
0
    int i = 0;  // Used after for.
6895
0
    for (; i < GetLayerCount(); ++i)
6896
0
    {
6897
0
        poLayer = GetLayer(i);
6898
6899
0
        if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6900
0
            break;
6901
0
        poLayer = nullptr;
6902
0
    }
6903
6904
0
    if (poLayer == nullptr)
6905
0
    {
6906
0
        CPLError(CE_Failure, CPLE_AppDefined,
6907
0
                 "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6908
0
        CSLDestroy(papszTokens);
6909
0
        return OGRERR_FAILURE;
6910
0
    }
6911
6912
0
    CSLDestroy(papszTokens);
6913
6914
    /* -------------------------------------------------------------------- */
6915
    /*      Delete it.                                                      */
6916
    /* -------------------------------------------------------------------- */
6917
6918
0
    return DeleteLayer(i);
6919
0
}
6920
6921
//! @endcond
6922
6923
/************************************************************************/
6924
/*                      GDALDatasetParseSQLType()                       */
6925
/************************************************************************/
6926
6927
/* All arguments will be altered */
6928
static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6929
                                            int &nPrecision)
6930
0
{
6931
0
    char *pszParenthesis = strchr(pszType, '(');
6932
0
    if (pszParenthesis)
6933
0
    {
6934
0
        nWidth = atoi(pszParenthesis + 1);
6935
0
        *pszParenthesis = '\0';
6936
0
        char *pszComma = strchr(pszParenthesis + 1, ',');
6937
0
        if (pszComma)
6938
0
            nPrecision = atoi(pszComma + 1);
6939
0
    }
6940
6941
0
    OGRFieldType eType = OFTString;
6942
0
    if (EQUAL(pszType, "INTEGER"))
6943
0
        eType = OFTInteger;
6944
0
    else if (EQUAL(pszType, "INTEGER[]"))
6945
0
        eType = OFTIntegerList;
6946
0
    else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6947
0
             EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6948
0
             EQUAL(pszType, "REAL") /* unofficial alias */)
6949
0
        eType = OFTReal;
6950
0
    else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6951
0
             EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6952
0
             EQUAL(pszType, "REAL[]") /* unofficial alias */)
6953
0
        eType = OFTRealList;
6954
0
    else if (EQUAL(pszType, "CHARACTER") ||
6955
0
             EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6956
0
             EQUAL(pszType, "STRING") /* unofficial alias */ ||
6957
0
             EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6958
0
        eType = OFTString;
6959
0
    else if (EQUAL(pszType, "TEXT[]") ||
6960
0
             EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6961
0
             EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6962
0
        eType = OFTStringList;
6963
0
    else if (EQUAL(pszType, "DATE"))
6964
0
        eType = OFTDate;
6965
0
    else if (EQUAL(pszType, "TIME"))
6966
0
        eType = OFTTime;
6967
0
    else if (EQUAL(pszType, "TIMESTAMP") ||
6968
0
             EQUAL(pszType, "DATETIME") /* unofficial alias */)
6969
0
        eType = OFTDateTime;
6970
0
    else
6971
0
        CPLError(CE_Warning, CPLE_NotSupported,
6972
0
                 "Unsupported column type '%s'. Defaulting to VARCHAR",
6973
0
                 pszType);
6974
6975
0
    return eType;
6976
0
}
6977
6978
/************************************************************************/
6979
/*                    ProcessSQLAlterTableAddColumn()                   */
6980
/*                                                                      */
6981
/*      The correct syntax for adding a column in the OGR SQL           */
6982
/*      dialect is:                                                     */
6983
/*                                                                      */
6984
/*       ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6985
/************************************************************************/
6986
6987
//! @cond Doxygen_Suppress
6988
OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6989
6990
0
{
6991
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6992
6993
    /* -------------------------------------------------------------------- */
6994
    /*      Do some general syntax checking.                                */
6995
    /* -------------------------------------------------------------------- */
6996
0
    const char *pszLayerName = nullptr;
6997
0
    const char *pszColumnName = nullptr;
6998
0
    int iTypeIndex = 0;
6999
0
    const int nTokens = CSLCount(papszTokens);
7000
7001
0
    if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7002
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
7003
0
        EQUAL(papszTokens[4], "COLUMN"))
7004
0
    {
7005
0
        pszLayerName = papszTokens[2];
7006
0
        pszColumnName = papszTokens[5];
7007
0
        iTypeIndex = 6;
7008
0
    }
7009
0
    else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
7010
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
7011
0
    {
7012
0
        pszLayerName = papszTokens[2];
7013
0
        pszColumnName = papszTokens[4];
7014
0
        iTypeIndex = 5;
7015
0
    }
7016
0
    else
7017
0
    {
7018
0
        CSLDestroy(papszTokens);
7019
0
        CPLError(CE_Failure, CPLE_AppDefined,
7020
0
                 "Syntax error in ALTER TABLE ADD COLUMN command.\n"
7021
0
                 "Was '%s'\n"
7022
0
                 "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
7023
0
                 "<columnname> <columntype>'",
7024
0
                 pszSQLCommand);
7025
0
        return OGRERR_FAILURE;
7026
0
    }
7027
7028
    /* -------------------------------------------------------------------- */
7029
    /*      Merge type components into a single string if there were split  */
7030
    /*      with spaces                                                     */
7031
    /* -------------------------------------------------------------------- */
7032
0
    CPLString osType;
7033
0
    for (int i = iTypeIndex; i < nTokens; ++i)
7034
0
    {
7035
0
        osType += papszTokens[i];
7036
0
        CPLFree(papszTokens[i]);
7037
0
    }
7038
0
    char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7039
0
    papszTokens[iTypeIndex + 1] = nullptr;
7040
7041
    /* -------------------------------------------------------------------- */
7042
    /*      Find the named layer.                                           */
7043
    /* -------------------------------------------------------------------- */
7044
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7045
0
    if (poLayer == nullptr)
7046
0
    {
7047
0
        CPLError(CE_Failure, CPLE_AppDefined,
7048
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7049
0
                 pszLayerName);
7050
0
        CSLDestroy(papszTokens);
7051
0
        return OGRERR_FAILURE;
7052
0
    }
7053
7054
    /* -------------------------------------------------------------------- */
7055
    /*      Add column.                                                     */
7056
    /* -------------------------------------------------------------------- */
7057
7058
0
    int nWidth = 0;
7059
0
    int nPrecision = 0;
7060
0
    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7061
0
    OGRFieldDefn oFieldDefn(pszColumnName, eType);
7062
0
    oFieldDefn.SetWidth(nWidth);
7063
0
    oFieldDefn.SetPrecision(nPrecision);
7064
7065
0
    CSLDestroy(papszTokens);
7066
7067
0
    return poLayer->CreateField(&oFieldDefn);
7068
0
}
7069
7070
/************************************************************************/
7071
/*                    ProcessSQLAlterTableDropColumn()                  */
7072
/*                                                                      */
7073
/*      The correct syntax for dropping a column in the OGR SQL         */
7074
/*      dialect is:                                                     */
7075
/*                                                                      */
7076
/*          ALTER TABLE <layername> DROP [COLUMN] <columnname>          */
7077
/************************************************************************/
7078
7079
OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7080
7081
0
{
7082
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7083
7084
    /* -------------------------------------------------------------------- */
7085
    /*      Do some general syntax checking.                                */
7086
    /* -------------------------------------------------------------------- */
7087
0
    const char *pszLayerName = nullptr;
7088
0
    const char *pszColumnName = nullptr;
7089
0
    if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7090
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7091
0
        EQUAL(papszTokens[4], "COLUMN"))
7092
0
    {
7093
0
        pszLayerName = papszTokens[2];
7094
0
        pszColumnName = papszTokens[5];
7095
0
    }
7096
0
    else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7097
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7098
0
    {
7099
0
        pszLayerName = papszTokens[2];
7100
0
        pszColumnName = papszTokens[4];
7101
0
    }
7102
0
    else
7103
0
    {
7104
0
        CSLDestroy(papszTokens);
7105
0
        CPLError(CE_Failure, CPLE_AppDefined,
7106
0
                 "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7107
0
                 "Was '%s'\n"
7108
0
                 "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7109
0
                 "<columnname>'",
7110
0
                 pszSQLCommand);
7111
0
        return OGRERR_FAILURE;
7112
0
    }
7113
7114
    /* -------------------------------------------------------------------- */
7115
    /*      Find the named layer.                                           */
7116
    /* -------------------------------------------------------------------- */
7117
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7118
0
    if (poLayer == nullptr)
7119
0
    {
7120
0
        CPLError(CE_Failure, CPLE_AppDefined,
7121
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7122
0
                 pszLayerName);
7123
0
        CSLDestroy(papszTokens);
7124
0
        return OGRERR_FAILURE;
7125
0
    }
7126
7127
    /* -------------------------------------------------------------------- */
7128
    /*      Find the field.                                                 */
7129
    /* -------------------------------------------------------------------- */
7130
7131
0
    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7132
0
    if (nFieldIndex < 0)
7133
0
    {
7134
0
        CPLError(CE_Failure, CPLE_AppDefined,
7135
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7136
0
                 pszColumnName);
7137
0
        CSLDestroy(papszTokens);
7138
0
        return OGRERR_FAILURE;
7139
0
    }
7140
7141
    /* -------------------------------------------------------------------- */
7142
    /*      Remove it.                                                      */
7143
    /* -------------------------------------------------------------------- */
7144
7145
0
    CSLDestroy(papszTokens);
7146
7147
0
    return poLayer->DeleteField(nFieldIndex);
7148
0
}
7149
7150
/************************************************************************/
7151
/*                 ProcessSQLAlterTableRenameColumn()                   */
7152
/*                                                                      */
7153
/*      The correct syntax for renaming a column in the OGR SQL         */
7154
/*      dialect is:                                                     */
7155
/*                                                                      */
7156
/*       ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7157
/************************************************************************/
7158
7159
OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7160
7161
0
{
7162
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7163
7164
    /* -------------------------------------------------------------------- */
7165
    /*      Do some general syntax checking.                                */
7166
    /* -------------------------------------------------------------------- */
7167
0
    const char *pszLayerName = nullptr;
7168
0
    const char *pszOldColName = nullptr;
7169
0
    const char *pszNewColName = nullptr;
7170
0
    if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7171
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7172
0
        EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7173
0
    {
7174
0
        pszLayerName = papszTokens[2];
7175
0
        pszOldColName = papszTokens[5];
7176
0
        pszNewColName = papszTokens[7];
7177
0
    }
7178
0
    else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7179
0
             EQUAL(papszTokens[1], "TABLE") &&
7180
0
             EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7181
0
    {
7182
0
        pszLayerName = papszTokens[2];
7183
0
        pszOldColName = papszTokens[4];
7184
0
        pszNewColName = papszTokens[6];
7185
0
    }
7186
0
    else
7187
0
    {
7188
0
        CSLDestroy(papszTokens);
7189
0
        CPLError(CE_Failure, CPLE_AppDefined,
7190
0
                 "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7191
0
                 "Was '%s'\n"
7192
0
                 "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7193
0
                 "<columnname> TO <newname>'",
7194
0
                 pszSQLCommand);
7195
0
        return OGRERR_FAILURE;
7196
0
    }
7197
7198
    /* -------------------------------------------------------------------- */
7199
    /*      Find the named layer.                                           */
7200
    /* -------------------------------------------------------------------- */
7201
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7202
0
    if (poLayer == nullptr)
7203
0
    {
7204
0
        CPLError(CE_Failure, CPLE_AppDefined,
7205
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7206
0
                 pszLayerName);
7207
0
        CSLDestroy(papszTokens);
7208
0
        return OGRERR_FAILURE;
7209
0
    }
7210
7211
    /* -------------------------------------------------------------------- */
7212
    /*      Find the field.                                                 */
7213
    /* -------------------------------------------------------------------- */
7214
7215
0
    const int nFieldIndex =
7216
0
        poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7217
0
    if (nFieldIndex < 0)
7218
0
    {
7219
0
        CPLError(CE_Failure, CPLE_AppDefined,
7220
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7221
0
                 pszOldColName);
7222
0
        CSLDestroy(papszTokens);
7223
0
        return OGRERR_FAILURE;
7224
0
    }
7225
7226
    /* -------------------------------------------------------------------- */
7227
    /*      Rename column.                                                  */
7228
    /* -------------------------------------------------------------------- */
7229
0
    OGRFieldDefn *poOldFieldDefn =
7230
0
        poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7231
0
    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7232
0
    oNewFieldDefn.SetName(pszNewColName);
7233
7234
0
    CSLDestroy(papszTokens);
7235
7236
0
    return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7237
0
                                   ALTER_NAME_FLAG);
7238
0
}
7239
7240
/************************************************************************/
7241
/*                 ProcessSQLAlterTableAlterColumn()                    */
7242
/*                                                                      */
7243
/*      The correct syntax for altering the type of a column in the     */
7244
/*      OGR SQL dialect is:                                             */
7245
/*                                                                      */
7246
/*   ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7247
/************************************************************************/
7248
7249
OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7250
7251
0
{
7252
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7253
7254
    /* -------------------------------------------------------------------- */
7255
    /*      Do some general syntax checking.                                */
7256
    /* -------------------------------------------------------------------- */
7257
0
    const char *pszLayerName = nullptr;
7258
0
    const char *pszColumnName = nullptr;
7259
0
    int iTypeIndex = 0;
7260
0
    const int nTokens = CSLCount(papszTokens);
7261
7262
0
    if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7263
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7264
0
        EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7265
0
    {
7266
0
        pszLayerName = papszTokens[2];
7267
0
        pszColumnName = papszTokens[5];
7268
0
        iTypeIndex = 7;
7269
0
    }
7270
0
    else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7271
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7272
0
             EQUAL(papszTokens[5], "TYPE"))
7273
0
    {
7274
0
        pszLayerName = papszTokens[2];
7275
0
        pszColumnName = papszTokens[4];
7276
0
        iTypeIndex = 6;
7277
0
    }
7278
0
    else
7279
0
    {
7280
0
        CSLDestroy(papszTokens);
7281
0
        CPLError(CE_Failure, CPLE_AppDefined,
7282
0
                 "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7283
0
                 "Was '%s'\n"
7284
0
                 "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7285
0
                 "<columnname> TYPE <columntype>'",
7286
0
                 pszSQLCommand);
7287
0
        return OGRERR_FAILURE;
7288
0
    }
7289
7290
    /* -------------------------------------------------------------------- */
7291
    /*      Merge type components into a single string if there were split  */
7292
    /*      with spaces                                                     */
7293
    /* -------------------------------------------------------------------- */
7294
0
    CPLString osType;
7295
0
    for (int i = iTypeIndex; i < nTokens; ++i)
7296
0
    {
7297
0
        osType += papszTokens[i];
7298
0
        CPLFree(papszTokens[i]);
7299
0
    }
7300
0
    char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7301
0
    papszTokens[iTypeIndex + 1] = nullptr;
7302
7303
    /* -------------------------------------------------------------------- */
7304
    /*      Find the named layer.                                           */
7305
    /* -------------------------------------------------------------------- */
7306
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7307
0
    if (poLayer == nullptr)
7308
0
    {
7309
0
        CPLError(CE_Failure, CPLE_AppDefined,
7310
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7311
0
                 pszLayerName);
7312
0
        CSLDestroy(papszTokens);
7313
0
        return OGRERR_FAILURE;
7314
0
    }
7315
7316
    /* -------------------------------------------------------------------- */
7317
    /*      Find the field.                                                 */
7318
    /* -------------------------------------------------------------------- */
7319
7320
0
    const int nFieldIndex =
7321
0
        poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7322
0
    if (nFieldIndex < 0)
7323
0
    {
7324
0
        CPLError(CE_Failure, CPLE_AppDefined,
7325
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7326
0
                 pszColumnName);
7327
0
        CSLDestroy(papszTokens);
7328
0
        return OGRERR_FAILURE;
7329
0
    }
7330
7331
    /* -------------------------------------------------------------------- */
7332
    /*      Alter column.                                                   */
7333
    /* -------------------------------------------------------------------- */
7334
7335
0
    OGRFieldDefn *poOldFieldDefn =
7336
0
        poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7337
0
    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7338
7339
0
    int nWidth = 0;
7340
0
    int nPrecision = 0;
7341
0
    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7342
0
    oNewFieldDefn.SetType(eType);
7343
0
    oNewFieldDefn.SetWidth(nWidth);
7344
0
    oNewFieldDefn.SetPrecision(nPrecision);
7345
7346
0
    int l_nFlags = 0;
7347
0
    if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7348
0
        l_nFlags |= ALTER_TYPE_FLAG;
7349
0
    if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7350
0
        poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7351
0
        l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7352
7353
0
    CSLDestroy(papszTokens);
7354
7355
0
    if (l_nFlags == 0)
7356
0
        return OGRERR_NONE;
7357
7358
0
    return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7359
0
}
7360
7361
//! @endcond
7362
7363
/************************************************************************/
7364
/*                             ExecuteSQL()                             */
7365
/************************************************************************/
7366
7367
/**
7368
 \brief Execute an SQL statement against the data store.
7369
7370
 The result of an SQL query is either NULL for statements that are in error,
7371
 or that have no results set, or an OGRLayer pointer representing a results
7372
 set from the query.  Note that this OGRLayer is in addition to the layers
7373
 in the data store and must be destroyed with
7374
 ReleaseResultSet() before the dataset is closed
7375
 (destroyed).
7376
7377
 This method is the same as the C function GDALDatasetExecuteSQL() and the
7378
 deprecated OGR_DS_ExecuteSQL().
7379
7380
 For more information on the SQL dialect supported internally by OGR
7381
 review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7382
 document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7383
 to the underlying RDBMS.
7384
7385
 Starting with OGR 1.10, the <a
7386
 href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7387
 also be used.
7388
7389
 @param pszStatement the SQL statement to execute.
7390
 @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7391
 @param pszDialect allows control of the statement dialect. If set to NULL, the
7392
 OGR SQL engine will be used, except for RDBMS drivers that will use their
7393
 dedicated SQL engine, unless OGRSQL is explicitly passed as the
7394
 dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7395
7396
 @return an OGRLayer containing the results of the query.  Deallocate with
7397
 ReleaseResultSet().
7398
7399
*/
7400
7401
OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7402
                                  OGRGeometry *poSpatialFilter,
7403
                                  const char *pszDialect)
7404
7405
0
{
7406
0
    return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7407
0
}
7408
7409
//! @cond Doxygen_Suppress
7410
OGRLayer *
7411
GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7412
                        const char *pszDialect,
7413
                        swq_select_parse_options *poSelectParseOptions)
7414
7415
0
{
7416
0
    if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7417
0
    {
7418
#ifdef SQLITE_ENABLED
7419
        return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7420
                                   pszDialect);
7421
#else
7422
0
        CPLError(CE_Failure, CPLE_NotSupported,
7423
0
                 "The SQLite driver needs to be compiled to support the "
7424
0
                 "SQLite SQL dialect");
7425
0
        return nullptr;
7426
0
#endif
7427
0
    }
7428
7429
0
    if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7430
0
        !EQUAL(pszDialect, "OGRSQL"))
7431
0
    {
7432
0
        std::string osDialectList = "'OGRSQL'";
7433
#ifdef SQLITE_ENABLED
7434
        osDialectList += ", 'SQLITE'";
7435
#endif
7436
0
        const char *pszDialects =
7437
0
            GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7438
0
        if (pszDialects)
7439
0
        {
7440
0
            const CPLStringList aosTokens(
7441
0
                CSLTokenizeString2(pszDialects, " ", 0));
7442
0
            for (int i = 0; i < aosTokens.size(); ++i)
7443
0
            {
7444
0
                if (!EQUAL(aosTokens[i], "OGRSQL") &&
7445
0
                    !EQUAL(aosTokens[i], "SQLITE"))
7446
0
                {
7447
0
                    osDialectList += ", '";
7448
0
                    osDialectList += aosTokens[i];
7449
0
                    osDialectList += "'";
7450
0
                }
7451
0
            }
7452
0
        }
7453
0
        CPLError(CE_Warning, CPLE_NotSupported,
7454
0
                 "Dialect '%s' is unsupported. Only supported dialects are %s. "
7455
0
                 "Defaulting to OGRSQL",
7456
0
                 pszDialect, osDialectList.c_str());
7457
0
    }
7458
7459
    /* -------------------------------------------------------------------- */
7460
    /*      Handle CREATE INDEX statements specially.                       */
7461
    /* -------------------------------------------------------------------- */
7462
0
    if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7463
0
    {
7464
0
        ProcessSQLCreateIndex(pszStatement);
7465
0
        return nullptr;
7466
0
    }
7467
7468
    /* -------------------------------------------------------------------- */
7469
    /*      Handle DROP INDEX statements specially.                         */
7470
    /* -------------------------------------------------------------------- */
7471
0
    if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7472
0
    {
7473
0
        ProcessSQLDropIndex(pszStatement);
7474
0
        return nullptr;
7475
0
    }
7476
7477
    /* -------------------------------------------------------------------- */
7478
    /*      Handle DROP TABLE statements specially.                         */
7479
    /* -------------------------------------------------------------------- */
7480
0
    if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7481
0
    {
7482
0
        ProcessSQLDropTable(pszStatement);
7483
0
        return nullptr;
7484
0
    }
7485
7486
    /* -------------------------------------------------------------------- */
7487
    /*      Handle ALTER TABLE statements specially.                        */
7488
    /* -------------------------------------------------------------------- */
7489
0
    if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7490
0
    {
7491
0
        char **papszTokens = CSLTokenizeString(pszStatement);
7492
0
        const int nTokens = CSLCount(papszTokens);
7493
0
        if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7494
0
        {
7495
0
            ProcessSQLAlterTableAddColumn(pszStatement);
7496
0
            CSLDestroy(papszTokens);
7497
0
            return nullptr;
7498
0
        }
7499
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7500
0
        {
7501
0
            ProcessSQLAlterTableDropColumn(pszStatement);
7502
0
            CSLDestroy(papszTokens);
7503
0
            return nullptr;
7504
0
        }
7505
0
        else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7506
0
                 EQUAL(papszTokens[4], "TO"))
7507
0
        {
7508
0
            const char *pszSrcTableName = papszTokens[2];
7509
0
            const char *pszDstTableName = papszTokens[5];
7510
0
            auto poSrcLayer = GetLayerByName(pszSrcTableName);
7511
0
            if (poSrcLayer)
7512
0
            {
7513
0
                CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7514
0
            }
7515
0
            else
7516
0
            {
7517
0
                CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7518
0
            }
7519
0
            CSLDestroy(papszTokens);
7520
0
            return nullptr;
7521
0
        }
7522
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7523
0
        {
7524
0
            ProcessSQLAlterTableRenameColumn(pszStatement);
7525
0
            CSLDestroy(papszTokens);
7526
0
            return nullptr;
7527
0
        }
7528
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7529
0
        {
7530
0
            ProcessSQLAlterTableAlterColumn(pszStatement);
7531
0
            CSLDestroy(papszTokens);
7532
0
            return nullptr;
7533
0
        }
7534
0
        else
7535
0
        {
7536
0
            CPLError(CE_Failure, CPLE_AppDefined,
7537
0
                     "Unsupported ALTER TABLE command : %s", pszStatement);
7538
0
            CSLDestroy(papszTokens);
7539
0
            return nullptr;
7540
0
        }
7541
0
    }
7542
7543
    /* -------------------------------------------------------------------- */
7544
    /*      Preparse the SQL statement.                                     */
7545
    /* -------------------------------------------------------------------- */
7546
0
    swq_select *psSelectInfo = new swq_select();
7547
0
    swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7548
0
    if (poSelectParseOptions != nullptr)
7549
0
        poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7550
0
    if (psSelectInfo->preparse(pszStatement,
7551
0
                               poCustomFuncRegistrar != nullptr) != CE_None)
7552
0
    {
7553
0
        delete psSelectInfo;
7554
0
        return nullptr;
7555
0
    }
7556
7557
    /* -------------------------------------------------------------------- */
7558
    /*      If there is no UNION ALL, build result layer.                   */
7559
    /* -------------------------------------------------------------------- */
7560
0
    if (psSelectInfo->poOtherSelect == nullptr)
7561
0
    {
7562
0
        return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7563
0
                                        pszDialect, poSelectParseOptions);
7564
0
    }
7565
7566
    /* -------------------------------------------------------------------- */
7567
    /*      Build result union layer.                                       */
7568
    /* -------------------------------------------------------------------- */
7569
0
    int nSrcLayers = 0;
7570
0
    OGRLayer **papoSrcLayers = nullptr;
7571
7572
0
    do
7573
0
    {
7574
0
        swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7575
0
        psSelectInfo->poOtherSelect = nullptr;
7576
7577
0
        OGRLayer *poLayer = BuildLayerFromSelectInfo(
7578
0
            psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7579
0
        if (poLayer == nullptr)
7580
0
        {
7581
            // Each source layer owns an independent select info.
7582
0
            for (int i = 0; i < nSrcLayers; ++i)
7583
0
                delete papoSrcLayers[i];
7584
0
            CPLFree(papoSrcLayers);
7585
7586
            // So we just have to destroy the remaining select info.
7587
0
            delete psNextSelectInfo;
7588
7589
0
            return nullptr;
7590
0
        }
7591
0
        else
7592
0
        {
7593
0
            papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7594
0
                papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7595
0
            papoSrcLayers[nSrcLayers] = poLayer;
7596
0
            ++nSrcLayers;
7597
7598
0
            psSelectInfo = psNextSelectInfo;
7599
0
        }
7600
0
    } while (psSelectInfo != nullptr);
7601
7602
0
    return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7603
0
}
7604
7605
//! @endcond
7606
7607
/************************************************************************/
7608
/*                              AbortSQL()                              */
7609
/************************************************************************/
7610
7611
/**
7612
 \brief Abort any SQL statement running in the data store.
7613
7614
 This function can be safely called from any thread (pending that the dataset
7615
 object is still alive). Driver implementations will make sure that it can be
7616
 called in a thread-safe way.
7617
7618
 This might not be implemented by all drivers. At time of writing, only SQLite,
7619
 GPKG and PG drivers implement it
7620
7621
 This method is the same as the C method GDALDatasetAbortSQL()
7622
7623
 @since GDAL 3.2.0
7624
7625
7626
*/
7627
7628
OGRErr GDALDataset::AbortSQL()
7629
0
{
7630
0
    CPLError(CE_Failure, CPLE_NotSupported,
7631
0
             "AbortSQL is not supported for this driver.");
7632
0
    return OGRERR_UNSUPPORTED_OPERATION;
7633
0
}
7634
7635
/************************************************************************/
7636
/*                      BuildLayerFromSelectInfo()                      */
7637
/************************************************************************/
7638
7639
struct GDALSQLParseInfo
7640
{
7641
    swq_field_list sFieldList;
7642
    int nExtraDSCount;
7643
    GDALDataset **papoExtraDS;
7644
    char *pszWHERE;
7645
};
7646
7647
OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7648
    swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7649
    const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7650
0
{
7651
0
    std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7652
7653
0
    std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7654
0
    GDALSQLParseInfo *psParseInfo =
7655
0
        BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7656
7657
0
    if (psParseInfo)
7658
0
    {
7659
0
        const auto nErrorCounter = CPLGetErrorCounter();
7660
0
        poResults = std::make_unique<OGRGenSQLResultsLayer>(
7661
0
            this, std::move(psSelectInfoUnique), poSpatialFilter,
7662
0
            psParseInfo->pszWHERE, pszDialect);
7663
0
        if (CPLGetErrorCounter() > nErrorCounter &&
7664
0
            CPLGetLastErrorType() != CE_None)
7665
0
            poResults.reset();
7666
0
    }
7667
7668
0
    DestroyParseInfo(psParseInfo);
7669
7670
0
    return poResults.release();
7671
0
}
7672
7673
/************************************************************************/
7674
/*                          DestroyParseInfo()                          */
7675
/************************************************************************/
7676
7677
//! @cond Doxygen_Suppress
7678
void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7679
0
{
7680
0
    if (psParseInfo == nullptr)
7681
0
        return;
7682
7683
0
    CPLFree(psParseInfo->sFieldList.names);
7684
0
    CPLFree(psParseInfo->sFieldList.types);
7685
0
    CPLFree(psParseInfo->sFieldList.table_ids);
7686
0
    CPLFree(psParseInfo->sFieldList.ids);
7687
7688
    // Release the datasets we have opened with OGROpenShared()
7689
    // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7690
    // has taken a reference on them, which it will release in its
7691
    // destructor.
7692
0
    for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7693
0
        GDALClose(psParseInfo->papoExtraDS[iEDS]);
7694
7695
0
    CPLFree(psParseInfo->papoExtraDS);
7696
0
    CPLFree(psParseInfo->pszWHERE);
7697
0
    CPLFree(psParseInfo);
7698
0
}
7699
7700
/************************************************************************/
7701
/*                           BuildParseInfo()                           */
7702
/************************************************************************/
7703
7704
GDALSQLParseInfo *
7705
GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7706
                            swq_select_parse_options *poSelectParseOptions)
7707
0
{
7708
0
    int nFirstLayerFirstSpecialFieldIndex = 0;
7709
7710
0
    GDALSQLParseInfo *psParseInfo =
7711
0
        static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7712
7713
    /* -------------------------------------------------------------------- */
7714
    /*      Validate that all the source tables are recognized, count       */
7715
    /*      fields.                                                         */
7716
    /* -------------------------------------------------------------------- */
7717
0
    int nFieldCount = 0;
7718
7719
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7720
0
    {
7721
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7722
0
        GDALDataset *poTableDS = this;
7723
7724
0
        if (psTableDef->data_source != nullptr)
7725
0
        {
7726
0
            poTableDS = GDALDataset::FromHandle(
7727
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7728
0
            if (poTableDS == nullptr)
7729
0
            {
7730
0
                if (strlen(CPLGetLastErrorMsg()) == 0)
7731
0
                    CPLError(CE_Failure, CPLE_AppDefined,
7732
0
                             "Unable to open secondary datasource "
7733
0
                             "`%s' required by JOIN.",
7734
0
                             psTableDef->data_source);
7735
7736
0
                DestroyParseInfo(psParseInfo);
7737
0
                return nullptr;
7738
0
            }
7739
7740
            // Keep in an array to release at the end of this function.
7741
0
            psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7742
0
                psParseInfo->papoExtraDS,
7743
0
                sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7744
0
            psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7745
0
        }
7746
7747
0
        OGRLayer *poSrcLayer =
7748
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7749
7750
0
        if (poSrcLayer == nullptr)
7751
0
        {
7752
0
            CPLError(CE_Failure, CPLE_AppDefined,
7753
0
                     "SELECT from table %s failed, no such table/featureclass.",
7754
0
                     psTableDef->table_name);
7755
7756
0
            DestroyParseInfo(psParseInfo);
7757
0
            return nullptr;
7758
0
        }
7759
7760
0
        nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7761
0
        if (iTable == 0 ||
7762
0
            (poSelectParseOptions &&
7763
0
             poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7764
0
            nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7765
7766
0
        const char *pszFID = poSrcLayer->GetFIDColumn();
7767
0
        if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7768
0
            poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7769
0
            nFieldCount++;
7770
0
    }
7771
7772
    /* -------------------------------------------------------------------- */
7773
    /*      Build the field list for all indicated tables.                  */
7774
    /* -------------------------------------------------------------------- */
7775
7776
0
    psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7777
0
    psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7778
7779
0
    psParseInfo->sFieldList.count = 0;
7780
0
    psParseInfo->sFieldList.names = static_cast<char **>(
7781
0
        CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7782
0
    psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7783
0
        sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7784
0
    psParseInfo->sFieldList.table_ids = static_cast<int *>(
7785
0
        CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7786
0
    psParseInfo->sFieldList.ids = static_cast<int *>(
7787
0
        CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7788
7789
0
    bool bIsFID64 = false;
7790
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7791
0
    {
7792
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7793
0
        GDALDataset *poTableDS = this;
7794
7795
0
        if (psTableDef->data_source != nullptr)
7796
0
        {
7797
0
            poTableDS = GDALDataset::FromHandle(
7798
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7799
0
            CPLAssert(poTableDS != nullptr);
7800
0
            poTableDS->Dereference();
7801
0
        }
7802
7803
0
        OGRLayer *poSrcLayer =
7804
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7805
7806
0
        for (int iField = 0;
7807
0
             iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7808
0
        {
7809
0
            OGRFieldDefn *poFDefn =
7810
0
                poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7811
0
            const int iOutField = psParseInfo->sFieldList.count++;
7812
0
            psParseInfo->sFieldList.names[iOutField] =
7813
0
                const_cast<char *>(poFDefn->GetNameRef());
7814
0
            if (poFDefn->GetType() == OFTInteger)
7815
0
            {
7816
0
                if (poFDefn->GetSubType() == OFSTBoolean)
7817
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7818
0
                else
7819
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7820
0
            }
7821
0
            else if (poFDefn->GetType() == OFTInteger64)
7822
0
            {
7823
0
                if (poFDefn->GetSubType() == OFSTBoolean)
7824
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7825
0
                else
7826
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7827
0
            }
7828
0
            else if (poFDefn->GetType() == OFTReal)
7829
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7830
0
            else if (poFDefn->GetType() == OFTString)
7831
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7832
0
            else if (poFDefn->GetType() == OFTTime)
7833
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7834
0
            else if (poFDefn->GetType() == OFTDate)
7835
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7836
0
            else if (poFDefn->GetType() == OFTDateTime)
7837
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7838
0
            else
7839
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7840
7841
0
            psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7842
0
            psParseInfo->sFieldList.ids[iOutField] = iField;
7843
0
        }
7844
7845
0
        if (iTable == 0)
7846
0
        {
7847
0
            nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7848
0
        }
7849
7850
0
        if (iTable == 0 ||
7851
0
            (poSelectParseOptions &&
7852
0
             poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7853
0
        {
7854
7855
0
            for (int iField = 0;
7856
0
                 iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7857
0
                 iField++)
7858
0
            {
7859
0
                OGRGeomFieldDefn *poFDefn =
7860
0
                    poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7861
0
                const int iOutField = psParseInfo->sFieldList.count++;
7862
0
                psParseInfo->sFieldList.names[iOutField] =
7863
0
                    const_cast<char *>(poFDefn->GetNameRef());
7864
0
                if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7865
0
                    psParseInfo->sFieldList.names[iOutField] =
7866
0
                        const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7867
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7868
7869
0
                psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7870
0
                psParseInfo->sFieldList.ids[iOutField] =
7871
0
                    GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7872
0
                        poSrcLayer->GetLayerDefn(), iField);
7873
0
            }
7874
0
        }
7875
7876
0
        if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7877
0
            EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7878
0
        {
7879
0
            bIsFID64 = true;
7880
0
        }
7881
0
    }
7882
7883
    /* -------------------------------------------------------------------- */
7884
    /*      Expand '*' in 'SELECT *' now before we add the pseudo fields    */
7885
    /* -------------------------------------------------------------------- */
7886
0
    const bool bAlwaysPrefixWithTableName =
7887
0
        poSelectParseOptions &&
7888
0
        poSelectParseOptions->bAlwaysPrefixWithTableName;
7889
0
    if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7890
0
                                      bAlwaysPrefixWithTableName) != CE_None)
7891
0
    {
7892
0
        DestroyParseInfo(psParseInfo);
7893
0
        return nullptr;
7894
0
    }
7895
7896
0
    for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7897
0
    {
7898
0
        psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7899
0
            const_cast<char *>(SpecialFieldNames[iField]);
7900
0
        psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7901
0
            (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7902
0
                                            : SpecialFieldTypes[iField];
7903
0
        psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7904
0
        psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7905
0
            nFirstLayerFirstSpecialFieldIndex + iField;
7906
0
        psParseInfo->sFieldList.count++;
7907
0
    }
7908
7909
    /* In the case a layer has an explicit FID column name, then add it */
7910
    /* so it can be selected */
7911
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7912
0
    {
7913
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7914
0
        GDALDataset *poTableDS = this;
7915
7916
0
        if (psTableDef->data_source != nullptr)
7917
0
        {
7918
0
            poTableDS = GDALDataset::FromHandle(
7919
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7920
0
            CPLAssert(poTableDS != nullptr);
7921
0
            poTableDS->Dereference();
7922
0
        }
7923
7924
0
        OGRLayer *poSrcLayer =
7925
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7926
7927
0
        const char *pszFID = poSrcLayer->GetFIDColumn();
7928
0
        if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7929
0
            poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7930
0
        {
7931
0
            const int iOutField = psParseInfo->sFieldList.count++;
7932
0
            psParseInfo->sFieldList.names[iOutField] =
7933
0
                const_cast<char *>(pszFID);
7934
0
            if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7935
0
                EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7936
0
            {
7937
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7938
0
            }
7939
0
            else
7940
0
            {
7941
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7942
0
            }
7943
0
            psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7944
0
            psParseInfo->sFieldList.ids[iOutField] =
7945
0
                poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7946
0
        }
7947
0
    }
7948
7949
    /* -------------------------------------------------------------------- */
7950
    /*      Finish the parse operation.                                     */
7951
    /* -------------------------------------------------------------------- */
7952
0
    if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7953
0
        CE_None)
7954
0
    {
7955
0
        DestroyParseInfo(psParseInfo);
7956
0
        return nullptr;
7957
0
    }
7958
7959
    /* -------------------------------------------------------------------- */
7960
    /*      Extract the WHERE expression to use separately.                 */
7961
    /* -------------------------------------------------------------------- */
7962
0
    if (psSelectInfo->where_expr != nullptr)
7963
0
    {
7964
0
        psParseInfo->pszWHERE =
7965
0
            psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7966
        // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7967
0
    }
7968
7969
0
    return psParseInfo;
7970
0
}
7971
7972
//! @endcond
7973
7974
/************************************************************************/
7975
/*                          ReleaseResultSet()                          */
7976
/************************************************************************/
7977
7978
/**
7979
 \brief Release results of ExecuteSQL().
7980
7981
 This method should only be used to deallocate OGRLayers resulting from
7982
 an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
7983
 results set before destroying the GDALDataset may cause errors.
7984
7985
 This method is the same as the C function GDALDatasetReleaseResultSet() and the
7986
 deprecated OGR_DS_ReleaseResultSet().
7987
7988
 @param poResultsSet the result of a previous ExecuteSQL() call.
7989
*/
7990
7991
void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7992
7993
0
{
7994
0
    delete poResultsSet;
7995
0
}
7996
7997
/************************************************************************/
7998
/*                           GetStyleTable()                            */
7999
/************************************************************************/
8000
8001
/**
8002
 \brief Returns dataset style table.
8003
8004
 This method is the same as the C function GDALDatasetGetStyleTable() and the
8005
 deprecated OGR_DS_GetStyleTable().
8006
8007
 @return pointer to a style table which should not be modified or freed by the
8008
 caller.
8009
*/
8010
8011
OGRStyleTable *GDALDataset::GetStyleTable()
8012
0
{
8013
0
    return m_poStyleTable;
8014
0
}
8015
8016
/************************************************************************/
8017
/*                       SetStyleTableDirectly()                        */
8018
/************************************************************************/
8019
8020
/**
8021
 \brief Set dataset style table.
8022
8023
 This method operate exactly as SetStyleTable() except that it
8024
 assumes ownership of the passed table.
8025
8026
 This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8027
 and the deprecated OGR_DS_SetStyleTableDirectly().
8028
8029
 @param poStyleTable pointer to style table to set
8030
8031
*/
8032
void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8033
0
{
8034
0
    if (m_poStyleTable)
8035
0
        delete m_poStyleTable;
8036
0
    m_poStyleTable = poStyleTable;
8037
0
}
8038
8039
/************************************************************************/
8040
/*                           SetStyleTable()                            */
8041
/************************************************************************/
8042
8043
/**
8044
 \brief Set dataset style table.
8045
8046
 This method operate exactly as SetStyleTableDirectly() except
8047
 that it does not assume ownership of the passed table.
8048
8049
 This method is the same as the C function GDALDatasetSetStyleTable() and the
8050
 deprecated OGR_DS_SetStyleTable().
8051
8052
 @param poStyleTable pointer to style table to set
8053
8054
*/
8055
8056
void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8057
0
{
8058
0
    if (m_poStyleTable)
8059
0
        delete m_poStyleTable;
8060
0
    if (poStyleTable)
8061
0
        m_poStyleTable = poStyleTable->Clone();
8062
0
}
8063
8064
/************************************************************************/
8065
/*                        IsGenericSQLDialect()                         */
8066
/************************************************************************/
8067
8068
//! @cond Doxygen_Suppress
8069
int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8070
0
{
8071
0
    return pszDialect != nullptr &&
8072
0
           (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8073
0
}
8074
8075
//! @endcond
8076
8077
/************************************************************************/
8078
/*                           GetLayerCount()                            */
8079
/************************************************************************/
8080
8081
/**
8082
 \brief Get the number of layers in this dataset.
8083
8084
 This method is the same as the C function GDALDatasetGetLayerCount(),
8085
 and the deprecated OGR_DS_GetLayerCount().
8086
8087
 Note that even if this method is const, there is no guarantee it can be
8088
 safely called by concurrent threads on the same GDALDataset object.
8089
8090
 @return layer count.
8091
*/
8092
8093
int GDALDataset::GetLayerCount() const
8094
0
{
8095
0
    return 0;
8096
0
}
8097
8098
/************************************************************************/
8099
/*                              GetLayer()                              */
8100
/************************************************************************/
8101
8102
/**
8103
 \fn const GDALDataset::GetLayer(int) const
8104
 \brief Fetch a layer by index.
8105
8106
 The returned layer remains owned by the
8107
 GDALDataset and should not be deleted by the application.
8108
8109
 Note that even if this method is const, there is no guarantee it can be
8110
 safely called by concurrent threads on the same GDALDataset object.
8111
8112
 See GetLayers() for a C++ iterator version of this method.
8113
8114
 This method is the same as the C function GDALDatasetGetLayer() and the
8115
 deprecated OGR_DS_GetLayer().
8116
8117
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8118
8119
 @return the layer, or NULL if iLayer is out of range or an error occurs.
8120
8121
 @see GetLayers()
8122
8123
 @since GDAL 3.12
8124
*/
8125
8126
const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8127
0
{
8128
0
    return nullptr;
8129
0
}
8130
8131
/**
8132
 \fn GDALDataset::GetLayer(int)
8133
 \brief Fetch a layer by index.
8134
8135
 The returned layer remains owned by the
8136
 GDALDataset and should not be deleted by the application.
8137
8138
 See GetLayers() for a C++ iterator version of this method.
8139
8140
 This method is the same as the C function GDALDatasetGetLayer() and the
8141
 deprecated OGR_DS_GetLayer().
8142
8143
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8144
8145
 @return the layer, or NULL if iLayer is out of range or an error occurs.
8146
8147
 @see GetLayers()
8148
*/
8149
8150
/************************************************************************/
8151
/*                           IsLayerPrivate()                           */
8152
/************************************************************************/
8153
8154
/**
8155
 \fn GDALDataset::IsLayerPrivate(int)
8156
 \brief Returns true if the layer at the specified index is deemed a private or
8157
 system table, or an internal detail only.
8158
8159
 This method is the same as the C function GDALDatasetIsLayerPrivate().
8160
8161
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8162
8163
 @return true if the layer is a private or system table.
8164
8165
 @since GDAL 3.4
8166
*/
8167
8168
bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8169
0
{
8170
0
    return false;
8171
0
}
8172
8173
/************************************************************************/
8174
/*                            ResetReading()                            */
8175
/************************************************************************/
8176
8177
/**
8178
 \brief Reset feature reading to start on the first feature.
8179
8180
 This affects GetNextFeature().
8181
8182
 Depending on drivers, this may also have the side effect of calling
8183
 OGRLayer::ResetReading() on the layers of this dataset.
8184
8185
 This method is the same as the C function GDALDatasetResetReading().
8186
8187
*/
8188
void GDALDataset::ResetReading()
8189
0
{
8190
0
    if (!m_poPrivate)
8191
0
        return;
8192
0
    m_poPrivate->nCurrentLayerIdx = 0;
8193
0
    m_poPrivate->nLayerCount = -1;
8194
0
    m_poPrivate->poCurrentLayer = nullptr;
8195
0
    m_poPrivate->nFeatureReadInLayer = 0;
8196
0
    m_poPrivate->nFeatureReadInDataset = 0;
8197
0
    m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8198
0
    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8199
0
}
8200
8201
/************************************************************************/
8202
/*                      GDALDatasetResetReading()                       */
8203
/************************************************************************/
8204
8205
/**
8206
 \brief Reset feature reading to start on the first feature.
8207
8208
 This affects GDALDatasetGetNextFeature().
8209
8210
 Depending on drivers, this may also have the side effect of calling
8211
 OGR_L_ResetReading() on the layers of this dataset.
8212
8213
 This method is the same as the C++ method GDALDataset::ResetReading()
8214
8215
 @param hDS dataset handle
8216
*/
8217
void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8218
0
{
8219
0
    VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8220
8221
0
    return GDALDataset::FromHandle(hDS)->ResetReading();
8222
0
}
8223
8224
/************************************************************************/
8225
/*                           GetNextFeature()                           */
8226
/************************************************************************/
8227
8228
/**
8229
 \brief Fetch the next available feature from this dataset.
8230
8231
 This method is intended for the few drivers where OGRLayer::GetNextFeature()
8232
 is not efficient, but in general OGRLayer::GetNextFeature() is a more
8233
 natural API.
8234
8235
 See GetFeatures() for a C++ iterator version of this method.
8236
8237
 The returned feature becomes the responsibility of the caller to
8238
 delete with OGRFeature::DestroyFeature().
8239
8240
 Depending on the driver, this method may return features from layers in a
8241
 non sequential way. This is what may happen when the
8242
 ODsCRandomLayerRead capability is declared (for example for the
8243
 OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8244
 advised to use GDALDataset::GetNextFeature() instead of
8245
 OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8246
 implementation.
8247
8248
 The default implementation, used by most drivers, will
8249
 however iterate over each layer, and then over each feature within this
8250
 layer.
8251
8252
 This method takes into account spatial and attribute filters set on layers that
8253
 will be iterated upon.
8254
8255
 The ResetReading() method can be used to start at the beginning again.
8256
8257
 Depending on drivers, this may also have the side effect of calling
8258
 OGRLayer::GetNextFeature() on the layers of this dataset.
8259
8260
 This method is the same as the C function GDALDatasetGetNextFeature().
8261
8262
 @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8263
                          layer to which the object belongs to, or NULL.
8264
                          It is possible that the output of *ppoBelongingLayer
8265
                          to be NULL despite the feature not being NULL.
8266
 @param pdfProgressPct    a pointer to a double variable to receive the
8267
                          percentage progress (in [0,1] range), or NULL.
8268
                          On return, the pointed value might be negative if
8269
                          determining the progress is not possible.
8270
 @param pfnProgress       a progress callback to report progress (for
8271
                          GetNextFeature() calls that might have a long
8272
                          duration) and offer cancellation possibility, or NULL.
8273
 @param pProgressData     user data provided to pfnProgress, or NULL
8274
 @return a feature, or NULL if no more features are available.
8275
 @see GetFeatures()
8276
*/
8277
8278
OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8279
                                        double *pdfProgressPct,
8280
                                        GDALProgressFunc pfnProgress,
8281
                                        void *pProgressData)
8282
0
{
8283
0
    if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8284
0
    {
8285
0
        if (ppoBelongingLayer != nullptr)
8286
0
            *ppoBelongingLayer = nullptr;
8287
0
        if (pdfProgressPct != nullptr)
8288
0
            *pdfProgressPct = 1.0;
8289
0
        if (pfnProgress != nullptr)
8290
0
            pfnProgress(1.0, "", pProgressData);
8291
0
        return nullptr;
8292
0
    }
8293
8294
0
    if (m_poPrivate->poCurrentLayer == nullptr &&
8295
0
        (pdfProgressPct != nullptr || pfnProgress != nullptr))
8296
0
    {
8297
0
        if (m_poPrivate->nLayerCount < 0)
8298
0
        {
8299
0
            m_poPrivate->nLayerCount = GetLayerCount();
8300
0
        }
8301
8302
0
        if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8303
0
        {
8304
0
            m_poPrivate->nTotalFeatures = 0;
8305
0
            for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8306
0
            {
8307
0
                OGRLayer *poLayer = GetLayer(i);
8308
0
                if (poLayer == nullptr ||
8309
0
                    !poLayer->TestCapability(OLCFastFeatureCount))
8310
0
                {
8311
0
                    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8312
0
                    break;
8313
0
                }
8314
0
                GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8315
0
                if (nCount < 0)
8316
0
                {
8317
0
                    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8318
0
                    break;
8319
0
                }
8320
0
                m_poPrivate->nTotalFeatures += nCount;
8321
0
            }
8322
0
        }
8323
0
    }
8324
8325
0
    while (true)
8326
0
    {
8327
0
        if (m_poPrivate->poCurrentLayer == nullptr)
8328
0
        {
8329
0
            m_poPrivate->poCurrentLayer =
8330
0
                GetLayer(m_poPrivate->nCurrentLayerIdx);
8331
0
            if (m_poPrivate->poCurrentLayer == nullptr)
8332
0
            {
8333
0
                m_poPrivate->nCurrentLayerIdx = -1;
8334
0
                if (ppoBelongingLayer != nullptr)
8335
0
                    *ppoBelongingLayer = nullptr;
8336
0
                if (pdfProgressPct != nullptr)
8337
0
                    *pdfProgressPct = 1.0;
8338
0
                return nullptr;
8339
0
            }
8340
0
            m_poPrivate->poCurrentLayer->ResetReading();
8341
0
            m_poPrivate->nFeatureReadInLayer = 0;
8342
0
            if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8343
0
            {
8344
0
                if (m_poPrivate->poCurrentLayer->TestCapability(
8345
0
                        OLCFastFeatureCount))
8346
0
                    m_poPrivate->nTotalFeaturesInLayer =
8347
0
                        m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8348
0
                else
8349
0
                    m_poPrivate->nTotalFeaturesInLayer = 0;
8350
0
            }
8351
0
        }
8352
0
        OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8353
0
        if (poFeature == nullptr)
8354
0
        {
8355
0
            m_poPrivate->nCurrentLayerIdx++;
8356
0
            m_poPrivate->poCurrentLayer = nullptr;
8357
0
            continue;
8358
0
        }
8359
8360
0
        m_poPrivate->nFeatureReadInLayer++;
8361
0
        m_poPrivate->nFeatureReadInDataset++;
8362
0
        if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8363
0
        {
8364
0
            double dfPct = 0.0;
8365
0
            if (m_poPrivate->nTotalFeatures > 0)
8366
0
            {
8367
0
                dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8368
0
                        m_poPrivate->nTotalFeatures;
8369
0
            }
8370
0
            else
8371
0
            {
8372
0
                dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8373
0
                        m_poPrivate->nLayerCount;
8374
0
                if (m_poPrivate->nTotalFeaturesInLayer > 0)
8375
0
                {
8376
0
                    dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8377
0
                             m_poPrivate->nTotalFeaturesInLayer /
8378
0
                             m_poPrivate->nLayerCount;
8379
0
                }
8380
0
            }
8381
0
            if (pdfProgressPct)
8382
0
                *pdfProgressPct = dfPct;
8383
0
            if (pfnProgress)
8384
0
                pfnProgress(dfPct, "", nullptr);
8385
0
        }
8386
8387
0
        if (ppoBelongingLayer != nullptr)
8388
0
            *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8389
0
        return poFeature;
8390
0
    }
8391
0
}
8392
8393
/************************************************************************/
8394
/*                     GDALDatasetGetNextFeature()                      */
8395
/************************************************************************/
8396
/**
8397
 \brief Fetch the next available feature from this dataset.
8398
8399
 This method is intended for the few drivers where OGR_L_GetNextFeature()
8400
 is not efficient, but in general OGR_L_GetNextFeature() is a more
8401
 natural API.
8402
8403
 The returned feature becomes the responsibility of the caller to
8404
 delete with OGRFeature::DestroyFeature().
8405
8406
 Depending on the driver, this method may return features from layers in a
8407
 non sequential way. This is what may happen when the
8408
 ODsCRandomLayerRead capability is declared (for example for the
8409
 OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8410
 advised to use GDALDataset::GetNextFeature() instead of
8411
 OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8412
 implementation.
8413
8414
 The default implementation, used by most drivers, will
8415
 however iterate over each layer, and then over each feature within this
8416
 layer.
8417
8418
 This method takes into account spatial and attribute filters set on layers that
8419
 will be iterated upon.
8420
8421
 The ResetReading() method can be used to start at the beginning again.
8422
8423
 Depending on drivers, this may also have the side effect of calling
8424
 OGRLayer::GetNextFeature() on the layers of this dataset.
8425
8426
 This method is the same as the C++ method GDALDataset::GetNextFeature()
8427
8428
 @param hDS               dataset handle.
8429
 @param phBelongingLayer  a pointer to a OGRLayer* variable to receive the
8430
                          layer to which the object belongs to, or NULL.
8431
                          It is possible that the output of *ppoBelongingLayer
8432
                          to be NULL despite the feature not being NULL.
8433
 @param pdfProgressPct    a pointer to a double variable to receive the
8434
                          percentage progress (in [0,1] range), or NULL.
8435
                          On return, the pointed value might be negative if
8436
                          determining the progress is not possible.
8437
 @param pfnProgress       a progress callback to report progress (for
8438
                          GetNextFeature() calls that might have a long
8439
                          duration) and offer cancellation possibility, or NULL
8440
 @param pProgressData     user data provided to pfnProgress, or NULL
8441
 @return a feature, or NULL if no more features are available.
8442
*/
8443
OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8444
                                              OGRLayerH *phBelongingLayer,
8445
                                              double *pdfProgressPct,
8446
                                              GDALProgressFunc pfnProgress,
8447
                                              void *pProgressData)
8448
0
{
8449
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8450
8451
0
    return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8452
0
        reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8453
0
        pfnProgress, pProgressData));
8454
0
}
8455
8456
/************************************************************************/
8457
/*                           TestCapability()                           */
8458
/************************************************************************/
8459
8460
/**
8461
 \fn GDALDataset::TestCapability( const char * pszCap )
8462
 \brief Test if capability is available.
8463
8464
 One of the following dataset capability names can be passed into this
8465
 method, and a TRUE or FALSE value will be returned indicating whether or not
8466
 the capability is available for this object.
8467
8468
 <ul>
8469
  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8470
  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8471
          layers.<p>
8472
  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8473
          datasource support CreateGeomField() just after layer creation.<p>
8474
  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8475
          geometries.<p>
8476
  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8477
          transactions.<p>
8478
  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8479
          transactions through emulation.<p>
8480
  <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8481
          GetNextFeature() implementation, potentially returning features from
8482
          layers in a non sequential way.<p>
8483
  <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8484
         CreateFeature() on layers in a non sequential way.<p>
8485
  <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8486
  <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8487
  <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8488
  <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8489
  <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8490
 </ul>
8491
8492
 The \#define macro forms of the capability names should be used in preference
8493
 to the strings themselves to avoid misspelling.
8494
8495
 This method is the same as the C function GDALDatasetTestCapability() and the
8496
 deprecated OGR_DS_TestCapability().
8497
8498
 @param pszCap the capability to test.
8499
8500
 @return TRUE if capability available otherwise FALSE.
8501
*/
8502
8503
int GDALDataset::TestCapability(const char *pszCap) const
8504
0
{
8505
0
    if (EQUAL(pszCap, GDsCFastGetExtent) ||
8506
0
        EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8507
0
    {
8508
0
        for (auto &&poLayer : GetLayers())
8509
0
        {
8510
0
            if (!poLayer->TestCapability(OLCFastGetExtent))
8511
0
                return FALSE;
8512
0
        }
8513
0
        return TRUE;
8514
0
    }
8515
0
    return FALSE;
8516
0
}
8517
8518
/************************************************************************/
8519
/*                     GDALDatasetTestCapability()                      */
8520
/************************************************************************/
8521
8522
/**
8523
 \brief Test if capability is available.
8524
8525
 One of the following dataset capability names can be passed into this
8526
 function, and a TRUE or FALSE value will be returned indicating whether or not
8527
 the capability is available for this object.
8528
8529
 <ul>
8530
  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8531
  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8532
          layers.<p>
8533
  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8534
          datasource support CreateGeomField() just after layer creation.<p>
8535
  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8536
          geometries.<p>
8537
  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8538
          transactions.<p>
8539
  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8540
          transactions through emulation.<p>
8541
  <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8542
          GetNextFeature() implementation, potentially returning features from
8543
          layers in a non sequential way.<p>
8544
  <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8545
          CreateFeature() on layers in a non sequential way.<p>
8546
  <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8547
  <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8548
  <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8549
  <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8550
  <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8551
 </ul>
8552
8553
 The \#define macro forms of the capability names should be used in preference
8554
 to the strings themselves to avoid misspelling.
8555
8556
 This function is the same as the C++ method GDALDataset::TestCapability()
8557
8558
8559
 @param hDS the dataset handle.
8560
 @param pszCap the capability to test.
8561
8562
 @return TRUE if capability available otherwise FALSE.
8563
*/
8564
int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8565
8566
0
{
8567
0
    VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8568
0
    VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8569
8570
0
    return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8571
0
}
8572
8573
/************************************************************************/
8574
/*                          StartTransaction()                          */
8575
/************************************************************************/
8576
8577
/**
8578
 \fn GDALDataset::StartTransaction(int)
8579
 \brief For datasources which support transactions, StartTransaction creates a
8580
`transaction.
8581
8582
 If starting the transaction fails, will return
8583
 OGRERR_FAILURE. Datasources which do not support transactions will
8584
 always return OGRERR_UNSUPPORTED_OPERATION.
8585
8586
 Nested transactions are not supported.
8587
8588
 All changes done after the start of the transaction are definitely applied in
8589
 the datasource if CommitTransaction() is called. They may be canceled by
8590
 calling RollbackTransaction() instead.
8591
8592
 At the time of writing, transactions only apply on vector layers.
8593
8594
 Datasets that support transactions will advertise the ODsCTransactions
8595
 capability.  Use of transactions at dataset level is generally preferred to
8596
 transactions at layer level, whose scope is rarely limited to the layer from
8597
 which it was started.
8598
8599
 In case StartTransaction() fails, neither CommitTransaction() or
8600
 RollbackTransaction() should be called.
8601
8602
 If an error occurs after a successful StartTransaction(), the whole transaction
8603
 may or may not be implicitly canceled, depending on drivers. (e.g.  the PG
8604
 driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8605
 an explicit call to RollbackTransaction() should be done to keep things
8606
 balanced.
8607
8608
 By default, when bForce is set to FALSE, only "efficient" transactions will be
8609
 attempted. Some drivers may offer an emulation of transactions, but sometimes
8610
 with significant overhead, in which case the user must explicitly allow for
8611
 such an emulation by setting bForce to TRUE. Drivers that offer emulated
8612
 transactions should advertise the ODsCEmulatedTransactions capability (and not
8613
 ODsCTransactions).
8614
8615
 This function is the same as the C function GDALDatasetStartTransaction().
8616
8617
 @param bForce can be set to TRUE if an emulation, possibly slow, of a
8618
 transaction
8619
               mechanism is acceptable.
8620
8621
 @return OGRERR_NONE on success.
8622
*/
8623
8624
OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8625
0
{
8626
0
    return OGRERR_UNSUPPORTED_OPERATION;
8627
0
}
8628
8629
/************************************************************************/
8630
/*                    GDALDatasetStartTransaction()                     */
8631
/************************************************************************/
8632
8633
/**
8634
 \brief For datasources which support transactions, StartTransaction creates a
8635
 transaction.
8636
8637
 If starting the transaction fails, will return
8638
 OGRERR_FAILURE. Datasources which do not support transactions will
8639
 always return OGRERR_UNSUPPORTED_OPERATION.
8640
8641
 Nested transactions are not supported.
8642
8643
 All changes done after the start of the transaction are definitely applied in
8644
 the datasource if CommitTransaction() is called. They may be canceled by
8645
 calling RollbackTransaction() instead.
8646
8647
 At the time of writing, transactions only apply on vector layers.
8648
8649
 Datasets that support transactions will advertise the ODsCTransactions
8650
 capability.
8651
 Use of transactions at dataset level is generally preferred to transactions at
8652
 layer level, whose scope is rarely limited to the layer from which it was
8653
 started.
8654
8655
 In case StartTransaction() fails, neither CommitTransaction() or
8656
 RollbackTransaction() should be called.
8657
8658
 If an error occurs after a successful StartTransaction(), the whole
8659
 transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8660
 the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8661
 error, an explicit call to RollbackTransaction() should be done to keep things
8662
 balanced.
8663
8664
 By default, when bForce is set to FALSE, only "efficient" transactions will be
8665
 attempted. Some drivers may offer an emulation of transactions, but sometimes
8666
 with significant overhead, in which case the user must explicitly allow for
8667
 such an emulation by setting bForce to TRUE. Drivers that offer emulated
8668
 transactions should advertise the ODsCEmulatedTransactions capability (and not
8669
 ODsCTransactions).
8670
8671
 This function is the same as the C++ method GDALDataset::StartTransaction()
8672
8673
 @param hDS the dataset handle.
8674
 @param bForce can be set to TRUE if an emulation, possibly slow, of a
8675
 transaction
8676
               mechanism is acceptable.
8677
8678
 @return OGRERR_NONE on success.
8679
*/
8680
OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8681
0
{
8682
0
    VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8683
0
                      OGRERR_INVALID_HANDLE);
8684
8685
0
#ifdef OGRAPISPY_ENABLED
8686
0
    if (bOGRAPISpyEnabled)
8687
0
        OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8688
0
#endif
8689
8690
0
    return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8691
0
}
8692
8693
/************************************************************************/
8694
/*                         CommitTransaction()                          */
8695
/************************************************************************/
8696
8697
/**
8698
 \brief For datasources which support transactions, CommitTransaction commits a
8699
 transaction.
8700
8701
 If no transaction is active, or the commit fails, will return
8702
 OGRERR_FAILURE. Datasources which do not support transactions will
8703
 always return OGRERR_UNSUPPORTED_OPERATION.
8704
8705
 Depending on drivers, this may or may not abort layer sequential readings that
8706
 are active.
8707
8708
 This function is the same as the C function GDALDatasetCommitTransaction().
8709
8710
 @return OGRERR_NONE on success.
8711
*/
8712
OGRErr GDALDataset::CommitTransaction()
8713
0
{
8714
0
    return OGRERR_UNSUPPORTED_OPERATION;
8715
0
}
8716
8717
/************************************************************************/
8718
/*                    GDALDatasetCommitTransaction()                    */
8719
/************************************************************************/
8720
8721
/**
8722
 \brief For datasources which support transactions, CommitTransaction commits a
8723
 transaction.
8724
8725
 If no transaction is active, or the commit fails, will return
8726
 OGRERR_FAILURE. Datasources which do not support transactions will
8727
 always return OGRERR_UNSUPPORTED_OPERATION.
8728
8729
 Depending on drivers, this may or may not abort layer sequential readings that
8730
 are active.
8731
8732
 This function is the same as the C++ method GDALDataset::CommitTransaction()
8733
8734
 @return OGRERR_NONE on success.
8735
*/
8736
OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8737
0
{
8738
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8739
0
                      OGRERR_INVALID_HANDLE);
8740
8741
0
#ifdef OGRAPISPY_ENABLED
8742
0
    if (bOGRAPISpyEnabled)
8743
0
        OGRAPISpy_Dataset_CommitTransaction(hDS);
8744
0
#endif
8745
8746
0
    return GDALDataset::FromHandle(hDS)->CommitTransaction();
8747
0
}
8748
8749
/************************************************************************/
8750
/*                        RollbackTransaction()                         */
8751
/************************************************************************/
8752
8753
/**
8754
 \brief For datasources which support transactions, RollbackTransaction will
8755
 roll back a datasource to its state before the start of the current
8756
 transaction.
8757
 If no transaction is active, or the rollback fails, will return
8758
 OGRERR_FAILURE. Datasources which do not support transactions will
8759
 always return OGRERR_UNSUPPORTED_OPERATION.
8760
8761
 This function is the same as the C function GDALDatasetRollbackTransaction().
8762
8763
 @return OGRERR_NONE on success.
8764
*/
8765
OGRErr GDALDataset::RollbackTransaction()
8766
0
{
8767
0
    return OGRERR_UNSUPPORTED_OPERATION;
8768
0
}
8769
8770
/************************************************************************/
8771
/*                   GDALDatasetRollbackTransaction()                   */
8772
/************************************************************************/
8773
8774
/**
8775
 \brief For datasources which support transactions, RollbackTransaction will
8776
 roll back a datasource to its state before the start of the current
8777
 transaction.
8778
 If no transaction is active, or the rollback fails, will return
8779
 OGRERR_FAILURE. Datasources which do not support transactions will
8780
 always return OGRERR_UNSUPPORTED_OPERATION.
8781
8782
 This function is the same as the C++ method GDALDataset::RollbackTransaction().
8783
8784
 @return OGRERR_NONE on success.
8785
*/
8786
OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8787
0
{
8788
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8789
0
                      OGRERR_INVALID_HANDLE);
8790
8791
0
#ifdef OGRAPISPY_ENABLED
8792
0
    if (bOGRAPISpyEnabled)
8793
0
        OGRAPISpy_Dataset_RollbackTransaction(hDS);
8794
0
#endif
8795
8796
0
    return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8797
0
}
8798
8799
//! @cond Doxygen_Suppress
8800
8801
/************************************************************************/
8802
/*                     ShareLockWithParentDataset()                     */
8803
/************************************************************************/
8804
8805
/* To be used typically by the GTiff driver to link overview datasets */
8806
/* with their main dataset, so that they share the same lock */
8807
/* Cf https://github.com/OSGeo/gdal/issues/1488 */
8808
/* The parent dataset should remain alive while the this dataset is alive */
8809
8810
void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8811
0
{
8812
0
    if (m_poPrivate != nullptr)
8813
0
    {
8814
0
        m_poPrivate->poParentDataset = poParentDataset;
8815
0
    }
8816
0
}
8817
8818
/************************************************************************/
8819
/*                         SetQueryLoggerFunc()                         */
8820
/************************************************************************/
8821
8822
bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8823
                                     CPL_UNUSED void *context)
8824
0
{
8825
0
    return false;
8826
0
}
8827
8828
/************************************************************************/
8829
/*                           EnterReadWrite()                           */
8830
/************************************************************************/
8831
8832
int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8833
0
{
8834
0
    if (m_poPrivate == nullptr ||
8835
0
        IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8836
0
        return FALSE;
8837
8838
0
    if (m_poPrivate->poParentDataset)
8839
0
        return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8840
8841
0
    if (eAccess == GA_Update)
8842
0
    {
8843
0
        if (m_poPrivate->eStateReadWriteMutex ==
8844
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8845
0
        {
8846
            // In case dead-lock would occur, which is not impossible,
8847
            // this can be used to prevent it, but at the risk of other
8848
            // issues.
8849
0
            if (CPLTestBool(
8850
0
                    CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8851
0
            {
8852
0
                m_poPrivate->eStateReadWriteMutex =
8853
0
                    GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8854
0
            }
8855
0
            else
8856
0
            {
8857
0
                m_poPrivate->eStateReadWriteMutex =
8858
0
                    GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8859
0
            }
8860
0
        }
8861
0
        if (m_poPrivate->eStateReadWriteMutex ==
8862
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8863
0
        {
8864
            // There should be no race related to creating this mutex since
8865
            // it should be first created through IWriteBlock() / IRasterIO()
8866
            // and then GDALRasterBlock might call it from another thread.
8867
#ifdef DEBUG_VERBOSE
8868
            CPLDebug("GDAL",
8869
                     "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8870
                     CPLGetPID(), GetDescription());
8871
#endif
8872
0
            CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8873
8874
0
            const int nCountMutex =
8875
0
                m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8876
0
            if (nCountMutex == 0 && eRWFlag == GF_Read)
8877
0
            {
8878
0
                CPLReleaseMutex(m_poPrivate->hMutex);
8879
0
                for (int i = 0; i < nBands; i++)
8880
0
                {
8881
0
                    auto blockCache = papoBands[i]->poBandBlockCache;
8882
0
                    if (blockCache)
8883
0
                        blockCache->WaitCompletionPendingTasks();
8884
0
                }
8885
0
                CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8886
0
            }
8887
8888
0
            return TRUE;
8889
0
        }
8890
0
    }
8891
0
    return FALSE;
8892
0
}
8893
8894
/************************************************************************/
8895
/*                           LeaveReadWrite()                           */
8896
/************************************************************************/
8897
8898
void GDALDataset::LeaveReadWrite()
8899
0
{
8900
0
    if (m_poPrivate)
8901
0
    {
8902
0
        if (m_poPrivate->poParentDataset)
8903
0
        {
8904
0
            m_poPrivate->poParentDataset->LeaveReadWrite();
8905
0
            return;
8906
0
        }
8907
8908
0
        m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8909
0
        CPLReleaseMutex(m_poPrivate->hMutex);
8910
#ifdef DEBUG_VERBOSE
8911
        CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8912
                 CPLGetPID(), GetDescription());
8913
#endif
8914
0
    }
8915
0
}
8916
8917
/************************************************************************/
8918
/*                             InitRWLock()                             */
8919
/************************************************************************/
8920
8921
void GDALDataset::InitRWLock()
8922
0
{
8923
0
    if (m_poPrivate)
8924
0
    {
8925
0
        if (m_poPrivate->poParentDataset)
8926
0
        {
8927
0
            m_poPrivate->poParentDataset->InitRWLock();
8928
0
            return;
8929
0
        }
8930
8931
0
        if (m_poPrivate->eStateReadWriteMutex ==
8932
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8933
0
        {
8934
0
            if (EnterReadWrite(GF_Write))
8935
0
                LeaveReadWrite();
8936
0
        }
8937
0
    }
8938
0
}
8939
8940
/************************************************************************/
8941
/*                       DisableReadWriteMutex()                        */
8942
/************************************************************************/
8943
8944
// The mutex logic is broken in multi-threaded situations, for example
8945
// with 2 WarpedVRT datasets being read at the same time. In that
8946
// particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8947
// to disable it.
8948
void GDALDataset::DisableReadWriteMutex()
8949
0
{
8950
0
    if (m_poPrivate)
8951
0
    {
8952
0
        if (m_poPrivate->poParentDataset)
8953
0
        {
8954
0
            m_poPrivate->poParentDataset->DisableReadWriteMutex();
8955
0
            return;
8956
0
        }
8957
8958
0
        m_poPrivate->eStateReadWriteMutex =
8959
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8960
0
    }
8961
0
}
8962
8963
/************************************************************************/
8964
/*                    TemporarilyDropReadWriteLock()                    */
8965
/************************************************************************/
8966
8967
void GDALDataset::TemporarilyDropReadWriteLock()
8968
0
{
8969
0
    if (m_poPrivate == nullptr)
8970
0
        return;
8971
8972
0
    if (m_poPrivate->poParentDataset)
8973
0
    {
8974
0
        m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8975
0
        return;
8976
0
    }
8977
8978
0
#ifndef __COVERITY__
8979
0
    if (m_poPrivate->hMutex)
8980
0
    {
8981
#ifdef DEBUG_VERBOSE
8982
        CPLDebug("GDAL",
8983
                 "[Thread " CPL_FRMT_GIB "] "
8984
                 "Temporarily drop RW mutex for %s",
8985
                 CPLGetPID(), GetDescription());
8986
#endif
8987
0
        CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8988
0
        const int nCount =
8989
0
            m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8990
#ifdef DEBUG_EXTRA
8991
        m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8992
#endif
8993
0
        for (int i = 0; i < nCount + 1; i++)
8994
0
        {
8995
            // The mutex is recursive
8996
0
            CPLReleaseMutex(m_poPrivate->hMutex);
8997
0
        }
8998
0
    }
8999
0
#endif
9000
0
}
9001
9002
/************************************************************************/
9003
/*                       ReacquireReadWriteLock()                       */
9004
/************************************************************************/
9005
9006
void GDALDataset::ReacquireReadWriteLock()
9007
0
{
9008
0
    if (m_poPrivate == nullptr)
9009
0
        return;
9010
9011
0
    if (m_poPrivate->poParentDataset)
9012
0
    {
9013
0
        m_poPrivate->poParentDataset->ReacquireReadWriteLock();
9014
0
        return;
9015
0
    }
9016
9017
0
#ifndef __COVERITY__
9018
0
    if (m_poPrivate->hMutex)
9019
0
    {
9020
#ifdef DEBUG_VERBOSE
9021
        CPLDebug("GDAL",
9022
                 "[Thread " CPL_FRMT_GIB "] "
9023
                 "Reacquire temporarily dropped RW mutex for %s",
9024
                 CPLGetPID(), GetDescription());
9025
#endif
9026
0
        CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9027
0
        const int nCount =
9028
0
            m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9029
#ifdef DEBUG_EXTRA
9030
        CPLAssert(nCount ==
9031
                  m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9032
#endif
9033
0
        if (nCount == 0)
9034
0
            CPLReleaseMutex(m_poPrivate->hMutex);
9035
0
        for (int i = 0; i < nCount - 1; i++)
9036
0
        {
9037
            // The mutex is recursive
9038
0
            CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9039
0
        }
9040
0
    }
9041
0
#endif
9042
0
}
9043
9044
/************************************************************************/
9045
/*                            AcquireMutex()                            */
9046
/************************************************************************/
9047
9048
int GDALDataset::AcquireMutex()
9049
0
{
9050
0
    if (m_poPrivate == nullptr)
9051
0
        return 0;
9052
0
    if (m_poPrivate->poParentDataset)
9053
0
    {
9054
0
        return m_poPrivate->poParentDataset->AcquireMutex();
9055
0
    }
9056
9057
0
    return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9058
0
}
9059
9060
/************************************************************************/
9061
/*                            ReleaseMutex()                            */
9062
/************************************************************************/
9063
9064
void GDALDataset::ReleaseMutex()
9065
0
{
9066
0
    if (m_poPrivate)
9067
0
    {
9068
0
        if (m_poPrivate->poParentDataset)
9069
0
        {
9070
0
            m_poPrivate->poParentDataset->ReleaseMutex();
9071
0
            return;
9072
0
        }
9073
9074
0
        CPLReleaseMutex(m_poPrivate->hMutex);
9075
0
    }
9076
0
}
9077
9078
//! @endcond
9079
9080
/************************************************************************/
9081
/*               GDALDataset::Features::Iterator::Private               */
9082
/************************************************************************/
9083
9084
struct GDALDataset::Features::Iterator::Private
9085
{
9086
    GDALDataset::FeatureLayerPair m_oPair{};
9087
    GDALDataset *m_poDS = nullptr;
9088
    bool m_bEOF = true;
9089
};
9090
9091
GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9092
0
    : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9093
0
{
9094
0
    m_poPrivate->m_poDS = poDS;
9095
0
    if (bStart)
9096
0
    {
9097
0
        poDS->ResetReading();
9098
0
        m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9099
0
            &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9100
0
        m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9101
0
    }
9102
0
}
9103
9104
0
GDALDataset::Features::Iterator::~Iterator() = default;
9105
9106
const GDALDataset::FeatureLayerPair &
9107
GDALDataset::Features::Iterator::operator*() const
9108
0
{
9109
0
    return m_poPrivate->m_oPair;
9110
0
}
9111
9112
GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9113
0
{
9114
0
    m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9115
0
        &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9116
0
    m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9117
0
    return *this;
9118
0
}
9119
9120
bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9121
0
{
9122
0
    return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9123
0
}
9124
9125
/************************************************************************/
9126
/*                            GetFeatures()                             */
9127
/************************************************************************/
9128
9129
/** Function that return an iterable object over features in the dataset
9130
 * layer.
9131
 *
9132
 * This is a C++ iterator friendly version of GetNextFeature().
9133
 *
9134
 * Using this iterator for standard range-based loops is safe, but
9135
 * due to implementation limitations, you shouldn't try to access
9136
 * (dereference) more than one iterator step at a time, since the
9137
 * FeatureLayerPair reference which is returned is reused.
9138
 *
9139
 * Typical use is:
9140
 * \code{.cpp}
9141
 * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9142
 * {
9143
 *       std::cout << "Feature of layer " <<
9144
 *               oFeatureLayerPair.layer->GetName() << std::endl;
9145
 *       oFeatureLayerPair.feature->DumpReadable();
9146
 * }
9147
 * \endcode
9148
 *
9149
 * @see GetNextFeature()
9150
 *
9151
 */
9152
GDALDataset::Features GDALDataset::GetFeatures()
9153
0
{
9154
0
    return Features(this);
9155
0
}
9156
9157
/************************************************************************/
9158
/*                               begin()                                */
9159
/************************************************************************/
9160
9161
/**
9162
 \brief Return beginning of feature iterator.
9163
9164
*/
9165
9166
const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9167
0
{
9168
0
    return {m_poSelf, true};
9169
0
}
9170
9171
/************************************************************************/
9172
/*                                end()                                 */
9173
/************************************************************************/
9174
9175
/**
9176
 \brief Return end of feature iterator.
9177
9178
*/
9179
9180
const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9181
0
{
9182
0
    return {m_poSelf, false};
9183
0
}
9184
9185
/************************************************************************/
9186
/*                GDALDataset::Layers::Iterator::Private                */
9187
/************************************************************************/
9188
9189
struct GDALDataset::Layers::Iterator::Private
9190
{
9191
    OGRLayer *m_poLayer = nullptr;
9192
    int m_iCurLayer = 0;
9193
    int m_nLayerCount = 0;
9194
    GDALDataset *m_poDS = nullptr;
9195
};
9196
9197
0
GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9198
0
{
9199
0
}
9200
9201
// False positive of cppcheck 1.72
9202
// cppcheck-suppress uninitMemberVar
9203
GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9204
0
    : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9205
0
{
9206
0
}
9207
9208
GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9209
0
    : m_poPrivate(std::move(oOther.m_poPrivate))
9210
0
{
9211
0
}
9212
9213
GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9214
0
    : m_poPrivate(new Private())
9215
0
{
9216
0
    m_poPrivate->m_poDS = poDS;
9217
0
    m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9218
0
    if (bStart)
9219
0
    {
9220
0
        if (m_poPrivate->m_nLayerCount)
9221
0
            m_poPrivate->m_poLayer = poDS->GetLayer(0);
9222
0
    }
9223
0
    else
9224
0
    {
9225
0
        m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9226
0
    }
9227
0
}
9228
9229
0
GDALDataset::Layers::Iterator::~Iterator() = default;
9230
9231
// False positive of cppcheck 1.72
9232
// cppcheck-suppress operatorEqVarError
9233
GDALDataset::Layers::Iterator &
9234
GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9235
0
{
9236
0
    *m_poPrivate = *oOther.m_poPrivate;
9237
0
    return *this;
9238
0
}
9239
9240
GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9241
    GDALDataset::Layers::Iterator &&oOther) noexcept
9242
0
{
9243
0
    m_poPrivate = std::move(oOther.m_poPrivate);
9244
0
    return *this;
9245
0
}
9246
9247
OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9248
0
{
9249
0
    return m_poPrivate->m_poLayer;
9250
0
}
9251
9252
GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9253
0
{
9254
0
    m_poPrivate->m_iCurLayer++;
9255
0
    if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9256
0
    {
9257
0
        m_poPrivate->m_poLayer =
9258
0
            m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9259
0
    }
9260
0
    else
9261
0
    {
9262
0
        m_poPrivate->m_poLayer = nullptr;
9263
0
    }
9264
0
    return *this;
9265
0
}
9266
9267
GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9268
0
{
9269
0
    GDALDataset::Layers::Iterator temp = *this;
9270
0
    ++(*this);
9271
0
    return temp;
9272
0
}
9273
9274
bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9275
0
{
9276
0
    return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9277
0
}
9278
9279
/************************************************************************/
9280
/*                             GetLayers()                              */
9281
/************************************************************************/
9282
9283
/** Function that returns an iterable object over layers in the dataset.
9284
 *
9285
 * This is a C++ iterator friendly version of GetLayer().
9286
 *
9287
 * Typical use is:
9288
 * \code{.cpp}
9289
 * for( auto&& poLayer: poDS->GetLayers() )
9290
 * {
9291
 *       std::cout << "Layer  << poLayer->GetName() << std::endl;
9292
 * }
9293
 * \endcode
9294
 *
9295
 * @see GetLayer()
9296
 *
9297
 */
9298
GDALDataset::Layers GDALDataset::GetLayers()
9299
0
{
9300
0
    return Layers(this);
9301
0
}
9302
9303
/************************************************************************/
9304
/*                               begin()                                */
9305
/************************************************************************/
9306
9307
/**
9308
 \brief Return beginning of layer iterator.
9309
9310
*/
9311
9312
GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9313
0
{
9314
0
    return {m_poSelf, true};
9315
0
}
9316
9317
/************************************************************************/
9318
/*                                end()                                 */
9319
/************************************************************************/
9320
9321
/**
9322
 \brief Return end of layer iterator.
9323
9324
*/
9325
9326
GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9327
0
{
9328
0
    return {m_poSelf, false};
9329
0
}
9330
9331
/************************************************************************/
9332
/*                                size()                                */
9333
/************************************************************************/
9334
9335
/**
9336
 \brief Get the number of layers in this dataset.
9337
9338
 @return layer count.
9339
9340
*/
9341
9342
size_t GDALDataset::Layers::size() const
9343
0
{
9344
0
    return static_cast<size_t>(m_poSelf->GetLayerCount());
9345
0
}
9346
9347
/************************************************************************/
9348
/*                             operator[]()                             */
9349
/************************************************************************/
9350
/**
9351
 \brief Fetch a layer by index.
9352
9353
 The returned layer remains owned by the
9354
 GDALDataset and should not be deleted by the application.
9355
9356
 @param iLayer a layer number between 0 and size()-1.
9357
9358
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9359
9360
*/
9361
9362
OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9363
0
{
9364
0
    return m_poSelf->GetLayer(iLayer);
9365
0
}
9366
9367
/************************************************************************/
9368
/*                             operator[]()                             */
9369
/************************************************************************/
9370
/**
9371
 \brief Fetch a layer by index.
9372
9373
 The returned layer remains owned by the
9374
 GDALDataset and should not be deleted by the application.
9375
9376
 @param iLayer a layer number between 0 and size()-1.
9377
9378
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9379
9380
*/
9381
9382
OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9383
0
{
9384
0
    return m_poSelf->GetLayer(static_cast<int>(iLayer));
9385
0
}
9386
9387
/************************************************************************/
9388
/*                             operator[]()                             */
9389
/************************************************************************/
9390
/**
9391
 \brief Fetch a layer by name.
9392
9393
 The returned layer remains owned by the
9394
 GDALDataset and should not be deleted by the application.
9395
9396
 @param pszLayerName layer name
9397
9398
 @return the layer, or nullptr if pszLayerName does not match with a layer
9399
9400
*/
9401
9402
OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9403
0
{
9404
0
    return m_poSelf->GetLayerByName(pszLayerName);
9405
0
}
9406
9407
/************************************************************************/
9408
/*             GDALDataset::ConstLayers::Iterator::Private              */
9409
/************************************************************************/
9410
9411
struct GDALDataset::ConstLayers::Iterator::Private
9412
{
9413
    const OGRLayer *m_poLayer = nullptr;
9414
    int m_iCurLayer = 0;
9415
    int m_nLayerCount = 0;
9416
    const GDALDataset *m_poDS = nullptr;
9417
};
9418
9419
0
GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9420
0
{
9421
0
}
9422
9423
// False positive of cppcheck 1.72
9424
// cppcheck-suppress uninitMemberVar
9425
GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9426
0
    : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9427
0
{
9428
0
}
9429
9430
GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9431
0
    : m_poPrivate(std::move(oOther.m_poPrivate))
9432
0
{
9433
0
}
9434
9435
GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9436
                                             bool bStart)
9437
0
    : m_poPrivate(new Private())
9438
0
{
9439
0
    m_poPrivate->m_poDS = poDS;
9440
0
    m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9441
0
    if (bStart)
9442
0
    {
9443
0
        if (m_poPrivate->m_nLayerCount)
9444
0
            m_poPrivate->m_poLayer = poDS->GetLayer(0);
9445
0
    }
9446
0
    else
9447
0
    {
9448
0
        m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9449
0
    }
9450
0
}
9451
9452
0
GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9453
9454
// False positive of cppcheck 1.72
9455
// cppcheck-suppress operatorEqVarError
9456
GDALDataset::ConstLayers::Iterator &
9457
GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9458
0
{
9459
0
    *m_poPrivate = *oOther.m_poPrivate;
9460
0
    return *this;
9461
0
}
9462
9463
GDALDataset::ConstLayers::Iterator &
9464
GDALDataset::ConstLayers::Iterator::operator=(
9465
    GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9466
0
{
9467
0
    m_poPrivate = std::move(oOther.m_poPrivate);
9468
0
    return *this;
9469
0
}
9470
9471
const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9472
0
{
9473
0
    return m_poPrivate->m_poLayer;
9474
0
}
9475
9476
GDALDataset::ConstLayers::Iterator &
9477
GDALDataset::ConstLayers::Iterator::operator++()
9478
0
{
9479
0
    m_poPrivate->m_iCurLayer++;
9480
0
    if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9481
0
    {
9482
0
        m_poPrivate->m_poLayer =
9483
0
            m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9484
0
    }
9485
0
    else
9486
0
    {
9487
0
        m_poPrivate->m_poLayer = nullptr;
9488
0
    }
9489
0
    return *this;
9490
0
}
9491
9492
GDALDataset::ConstLayers::Iterator
9493
GDALDataset::ConstLayers::Iterator::operator++(int)
9494
0
{
9495
0
    GDALDataset::ConstLayers::Iterator temp = *this;
9496
0
    ++(*this);
9497
0
    return temp;
9498
0
}
9499
9500
bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9501
0
{
9502
0
    return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9503
0
}
9504
9505
/************************************************************************/
9506
/*                             GetLayers()                              */
9507
/************************************************************************/
9508
9509
/** Function that returns an iterable object over layers in the dataset.
9510
 *
9511
 * This is a C++ iterator friendly version of GetLayer().
9512
 *
9513
 * Typical use is:
9514
 * \code{.cpp}
9515
 * for( auto&& poLayer: poDS->GetLayers() )
9516
 * {
9517
 *       std::cout << "Layer  << poLayer->GetName() << std::endl;
9518
 * }
9519
 * \endcode
9520
 *
9521
 * @see GetLayer()
9522
 *
9523
 * @since GDAL 3.12
9524
 */
9525
GDALDataset::ConstLayers GDALDataset::GetLayers() const
9526
0
{
9527
0
    return ConstLayers(this);
9528
0
}
9529
9530
/************************************************************************/
9531
/*                               begin()                                */
9532
/************************************************************************/
9533
9534
/**
9535
 \brief Return beginning of layer iterator.
9536
9537
 @since GDAL 3.12
9538
*/
9539
9540
GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9541
0
{
9542
0
    return {m_poSelf, true};
9543
0
}
9544
9545
/************************************************************************/
9546
/*                                end()                                 */
9547
/************************************************************************/
9548
9549
/**
9550
 \brief Return end of layer iterator.
9551
9552
 @since GDAL 3.12
9553
*/
9554
9555
GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9556
0
{
9557
0
    return {m_poSelf, false};
9558
0
}
9559
9560
/************************************************************************/
9561
/*                                size()                                */
9562
/************************************************************************/
9563
9564
/**
9565
 \brief Get the number of layers in this dataset.
9566
9567
 @return layer count.
9568
9569
 @since GDAL 3.12
9570
*/
9571
9572
size_t GDALDataset::ConstLayers::size() const
9573
0
{
9574
0
    return static_cast<size_t>(m_poSelf->GetLayerCount());
9575
0
}
9576
9577
/************************************************************************/
9578
/*                             operator[]()                             */
9579
/************************************************************************/
9580
/**
9581
 \brief Fetch a layer by index.
9582
9583
 The returned layer remains owned by the
9584
 GDALDataset and should not be deleted by the application.
9585
9586
 @param iLayer a layer number between 0 and size()-1.
9587
9588
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9589
9590
 @since GDAL 3.12
9591
*/
9592
9593
const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9594
0
{
9595
0
    return m_poSelf->GetLayer(iLayer);
9596
0
}
9597
9598
/************************************************************************/
9599
/*                             operator[]()                             */
9600
/************************************************************************/
9601
/**
9602
 \brief Fetch a layer by index.
9603
9604
 The returned layer remains owned by the
9605
 GDALDataset and should not be deleted by the application.
9606
9607
 @param iLayer a layer number between 0 and size()-1.
9608
9609
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9610
9611
 @since GDAL 3.12
9612
*/
9613
9614
const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9615
0
{
9616
0
    return m_poSelf->GetLayer(static_cast<int>(iLayer));
9617
0
}
9618
9619
/************************************************************************/
9620
/*                             operator[]()                             */
9621
/************************************************************************/
9622
/**
9623
 \brief Fetch a layer by name.
9624
9625
 The returned layer remains owned by the
9626
 GDALDataset and should not be deleted by the application.
9627
9628
 @param pszLayerName layer name
9629
9630
 @return the layer, or nullptr if pszLayerName does not match with a layer
9631
9632
 @since GDAL 3.12
9633
*/
9634
9635
const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9636
0
{
9637
0
    return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9638
0
}
9639
9640
/************************************************************************/
9641
/*                GDALDataset::Bands::Iterator::Private                 */
9642
/************************************************************************/
9643
9644
struct GDALDataset::Bands::Iterator::Private
9645
{
9646
    GDALRasterBand *m_poBand = nullptr;
9647
    int m_iCurBand = 0;
9648
    int m_nBandCount = 0;
9649
    GDALDataset *m_poDS = nullptr;
9650
};
9651
9652
GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9653
0
    : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9654
0
{
9655
0
    m_poPrivate->m_poDS = poDS;
9656
0
    m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9657
0
    if (bStart)
9658
0
    {
9659
0
        if (m_poPrivate->m_nBandCount)
9660
0
            m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9661
0
    }
9662
0
    else
9663
0
    {
9664
0
        m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9665
0
    }
9666
0
}
9667
9668
0
GDALDataset::Bands::Iterator::~Iterator() = default;
9669
9670
GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9671
0
{
9672
0
    return m_poPrivate->m_poBand;
9673
0
}
9674
9675
GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9676
0
{
9677
0
    m_poPrivate->m_iCurBand++;
9678
0
    if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9679
0
    {
9680
0
        m_poPrivate->m_poBand =
9681
0
            m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9682
0
    }
9683
0
    else
9684
0
    {
9685
0
        m_poPrivate->m_poBand = nullptr;
9686
0
    }
9687
0
    return *this;
9688
0
}
9689
9690
bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9691
0
{
9692
0
    return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9693
0
}
9694
9695
/************************************************************************/
9696
/*                              GetBands()                              */
9697
/************************************************************************/
9698
9699
/** Function that returns an iterable object over GDALRasterBand in the dataset.
9700
 *
9701
 * This is a C++ iterator friendly version of GetRasterBand().
9702
 *
9703
 * Typical use is:
9704
 * \code{.cpp}
9705
 * for( auto&& poBand: poDS->GetBands() )
9706
 * {
9707
 *       std::cout << "Band  << poBand->GetDescription() << std::endl;
9708
 * }
9709
 * \endcode
9710
 *
9711
 * @see GetRasterBand()
9712
 *
9713
 */
9714
GDALDataset::Bands GDALDataset::GetBands()
9715
0
{
9716
0
    return Bands(this);
9717
0
}
9718
9719
/************************************************************************/
9720
/*                               begin()                                */
9721
/************************************************************************/
9722
9723
/**
9724
 \brief Return beginning of band iterator.
9725
9726
*/
9727
9728
const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9729
0
{
9730
0
    return {m_poSelf, true};
9731
0
}
9732
9733
/************************************************************************/
9734
/*                                end()                                 */
9735
/************************************************************************/
9736
9737
/**
9738
 \brief Return end of band iterator.
9739
9740
*/
9741
9742
const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9743
0
{
9744
0
    return {m_poSelf, false};
9745
0
}
9746
9747
/************************************************************************/
9748
/*                                size()                                */
9749
/************************************************************************/
9750
9751
/**
9752
 \brief Get the number of raster bands in this dataset.
9753
9754
 @return raster band count.
9755
9756
*/
9757
9758
size_t GDALDataset::Bands::size() const
9759
0
{
9760
0
    return static_cast<size_t>(m_poSelf->GetRasterCount());
9761
0
}
9762
9763
/************************************************************************/
9764
/*                             operator[]()                             */
9765
/************************************************************************/
9766
/**
9767
 \brief Fetch a raster band by index.
9768
9769
 The returned band remains owned by the
9770
 GDALDataset and should not be deleted by the application.
9771
9772
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9773
 consistent with the conventions of C/C++, i.e. starting at 0.
9774
9775
 @param iBand a band index between 0 and size()-1.
9776
9777
 @return the band, or nullptr if iBand is out of range or an error occurs.
9778
9779
*/
9780
9781
GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9782
0
{
9783
0
    return m_poSelf->GetRasterBand(1 + iBand);
9784
0
}
9785
9786
/************************************************************************/
9787
/*                             operator[]()                             */
9788
/************************************************************************/
9789
9790
/**
9791
 \brief Fetch a raster band by index.
9792
9793
 The returned band remains owned by the
9794
 GDALDataset and should not be deleted by the application.
9795
9796
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9797
 consistent with the conventions of C/C++, i.e. starting at 0.
9798
9799
 @param iBand a band index between 0 and size()-1.
9800
9801
 @return the band, or nullptr if iBand is out of range or an error occurs.
9802
9803
*/
9804
9805
GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9806
0
{
9807
0
    return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9808
0
}
9809
9810
/************************************************************************/
9811
/*              GDALDataset::ConstBands::Iterator::Private              */
9812
/************************************************************************/
9813
9814
struct GDALDataset::ConstBands::Iterator::Private
9815
{
9816
    const GDALRasterBand *m_poBand = nullptr;
9817
    int m_iCurBand = 0;
9818
    int m_nBandCount = 0;
9819
    const GDALDataset *m_poDS = nullptr;
9820
};
9821
9822
GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9823
                                            bool bStart)
9824
0
    : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9825
0
{
9826
0
    m_poPrivate->m_poDS = poDS;
9827
0
    m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9828
0
    if (bStart)
9829
0
    {
9830
0
        if (m_poPrivate->m_nBandCount)
9831
0
            m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9832
0
    }
9833
0
    else
9834
0
    {
9835
0
        m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9836
0
    }
9837
0
}
9838
9839
0
GDALDataset::ConstBands::Iterator::~Iterator() = default;
9840
9841
const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9842
0
{
9843
0
    return m_poPrivate->m_poBand;
9844
0
}
9845
9846
GDALDataset::ConstBands::Iterator &
9847
GDALDataset::ConstBands::Iterator::operator++()
9848
0
{
9849
0
    m_poPrivate->m_iCurBand++;
9850
0
    if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9851
0
    {
9852
0
        m_poPrivate->m_poBand =
9853
0
            m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9854
0
    }
9855
0
    else
9856
0
    {
9857
0
        m_poPrivate->m_poBand = nullptr;
9858
0
    }
9859
0
    return *this;
9860
0
}
9861
9862
bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9863
0
{
9864
0
    return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9865
0
}
9866
9867
/************************************************************************/
9868
/*                              GetBands()                              */
9869
/************************************************************************/
9870
9871
/** Function that returns an iterable object over GDALRasterBand in the dataset.
9872
 *
9873
 * This is a C++ iterator friendly version of GetRasterBand().
9874
 *
9875
 * Typical use is:
9876
 * \code{.cpp}
9877
 * for( const auto* poBand: poDS->GetConstBands() )
9878
 * {
9879
 *       std::cout << "Band  << poBand->GetDescription() << std::endl;
9880
 * }
9881
 * \endcode
9882
 *
9883
 * @see GetRasterBand()
9884
 *
9885
 * @since GDAL 3.12
9886
 */
9887
GDALDataset::ConstBands GDALDataset::GetBands() const
9888
0
{
9889
0
    return ConstBands(this);
9890
0
}
9891
9892
/************************************************************************/
9893
/*                               begin()                                */
9894
/************************************************************************/
9895
9896
/**
9897
 \brief Return beginning of band iterator.
9898
9899
 @since GDAL 3.12
9900
*/
9901
9902
const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9903
0
{
9904
0
    return {m_poSelf, true};
9905
0
}
9906
9907
/************************************************************************/
9908
/*                                end()                                 */
9909
/************************************************************************/
9910
9911
/**
9912
 \brief Return end of band iterator.
9913
9914
 @since GDAL 3.12
9915
*/
9916
9917
const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9918
0
{
9919
0
    return {m_poSelf, false};
9920
0
}
9921
9922
/************************************************************************/
9923
/*                                size()                                */
9924
/************************************************************************/
9925
9926
/**
9927
 \brief Get the number of raster bands in this dataset.
9928
9929
 @return raster band count.
9930
9931
 @since GDAL 3.12
9932
*/
9933
9934
size_t GDALDataset::ConstBands::size() const
9935
0
{
9936
0
    return static_cast<size_t>(m_poSelf->GetRasterCount());
9937
0
}
9938
9939
/************************************************************************/
9940
/*                             operator[]()                             */
9941
/************************************************************************/
9942
/**
9943
 \brief Fetch a raster band by index.
9944
9945
 The returned band remains owned by the
9946
 GDALDataset and should not be deleted by the application.
9947
9948
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9949
 consistent with the conventions of C/C++, i.e. starting at 0.
9950
9951
 @param iBand a band index between 0 and size()-1.
9952
9953
 @return the band, or nullptr if iBand is out of range or an error occurs.
9954
9955
 @since GDAL 3.12
9956
*/
9957
9958
const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9959
0
{
9960
0
    return m_poSelf->GetRasterBand(1 + iBand);
9961
0
}
9962
9963
/************************************************************************/
9964
/*                             operator[]()                             */
9965
/************************************************************************/
9966
9967
/**
9968
 \brief Fetch a raster band by index.
9969
9970
 The returned band remains owned by the
9971
 GDALDataset and should not be deleted by the application.
9972
9973
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9974
 consistent with the conventions of C/C++, i.e. starting at 0.
9975
9976
 @param iBand a band index between 0 and size()-1.
9977
9978
 @return the band, or nullptr if iBand is out of range or an error occurs.
9979
9980
 @since GDAL 3.12
9981
*/
9982
9983
const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9984
0
{
9985
0
    return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9986
0
}
9987
9988
/************************************************************************/
9989
/*                            GetRootGroup()                            */
9990
/************************************************************************/
9991
9992
/**
9993
 \brief Return the root GDALGroup of this dataset.
9994
9995
 Only valid for multidimensional datasets.
9996
9997
 This is the same as the C function GDALDatasetGetRootGroup().
9998
9999
 @since GDAL 3.1
10000
*/
10001
10002
std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
10003
0
{
10004
0
    return nullptr;
10005
0
}
10006
10007
/************************************************************************/
10008
/*                      GDALDatasetGetRootGroup()                       */
10009
/************************************************************************/
10010
10011
/** Return the root GDALGroup of this dataset.
10012
 *
10013
 * Only valid for multidimensional datasets.
10014
 *
10015
 * The returned value must be freed with GDALGroupRelease().
10016
 *
10017
 * This is the same as the C++ method GDALDataset::GetRootGroup().
10018
 *
10019
 * @since GDAL 3.1
10020
 */
10021
GDALGroupH GDALDatasetGetRootGroup(GDALDatasetH hDS)
10022
0
{
10023
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10024
0
    auto poGroup(GDALDataset::FromHandle(hDS)->GetRootGroup());
10025
0
    return poGroup ? new GDALGroupHS(poGroup) : nullptr;
10026
0
}
10027
10028
/************************************************************************/
10029
/*                        GDALDatasetAsMDArray()                        */
10030
/************************************************************************/
10031
10032
/** Return a view of this dataset as a 3D multidimensional GDALMDArray.
10033
 *
10034
 * If this dataset is not already marked as shared, it will be, so that the
10035
 * returned array holds a reference to it.
10036
 *
10037
 * If the dataset has a geotransform attached, the X and Y dimensions of the
10038
 * returned array will have an associated indexing variable.
10039
 *
10040
 * The currently supported list of options is:
10041
 * <ul>
10042
 * <li>DIM_ORDER=&lt;order&gt; where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
10043
 * "Band,Y,X" means that the first (slowest changing) dimension is Band
10044
 * and the last (fastest changing direction) is X
10045
 * "Y,X,Band" means that the first (slowest changing) dimension is Y
10046
 * and the last (fastest changing direction) is Band.
10047
 * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
10048
 * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
10049
 * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
10050
 * "Y,X,Band" is use.
10051
 * </li>
10052
 * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|&lt;BandMetadataItem&gt;:
10053
 * item from which to build the band indexing variable.
10054
 * <ul>
10055
 * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
10056
 * <li>"{None}" means that no band indexing variable must be created.</li>
10057
 * <li>"{Index}" means that the band index (starting at one) is used.</li>
10058
 * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
10059
 * <li>&lt;BandMetadataItem&gt; is the name of a band metadata item to use.</li>
10060
 * </ul>
10061
 * </li>
10062
 * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
10063
 * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
10064
 * Defaults to String.
10065
 * </li>
10066
 * <li>BAND_DIM_NAME=&lt;string&gt;: Name of the band dimension.
10067
 * Defaults to "Band".
10068
 * </li>
10069
 * <li>X_DIM_NAME=&lt;string&gt;: Name of the X dimension. Defaults to "X".
10070
 * </li>
10071
 * <li>Y_DIM_NAME=&lt;string&gt;: Name of the Y dimension. Defaults to "Y".
10072
 * </li>
10073
 * </ul>
10074
 *
10075
 * The returned pointer must be released with GDALMDArrayRelease().
10076
 *
10077
 * The "reverse" methods are GDALRasterBand::AsMDArray() and
10078
 * GDALDataset::AsMDArray()
10079
 *
10080
 * This is the same as the C++ method GDALDataset::AsMDArray().
10081
 *
10082
 * @param hDS Dataset handle.
10083
 * @param papszOptions Null-terminated list of strings, or nullptr.
10084
 * @return a new array, or NULL.
10085
 *
10086
 * @since GDAL 3.12
10087
 */
10088
GDALMDArrayH GDALDatasetAsMDArray(GDALDatasetH hDS, CSLConstList papszOptions)
10089
0
{
10090
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10091
0
    auto poArray(GDALDataset::FromHandle(hDS)->AsMDArray(papszOptions));
10092
0
    if (!poArray)
10093
0
        return nullptr;
10094
0
    return new GDALMDArrayHS(poArray);
10095
0
}
10096
10097
/************************************************************************/
10098
/*                         GetRawBinaryLayout()                         */
10099
/************************************************************************/
10100
10101
//! @cond Doxygen_Suppress
10102
/**
10103
 \brief Return the layout of a dataset that can be considered as a raw binary
10104
 format.
10105
10106
 @param sLayout Structure that will be set if the dataset is a raw binary one.
10107
 @return true if the dataset is a raw binary one.
10108
 @since GDAL 3.1
10109
*/
10110
10111
bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
10112
0
{
10113
0
    CPL_IGNORE_RET_VAL(sLayout);
10114
0
    return false;
10115
0
}
10116
10117
//! @endcond
10118
10119
/************************************************************************/
10120
/*                          ClearStatistics()                           */
10121
/************************************************************************/
10122
10123
/**
10124
 \brief Clear statistics
10125
10126
 Only implemented for now in PAM supported datasets
10127
10128
 This is the same as the C function GDALDatasetClearStatistics().
10129
10130
 @since GDAL 3.2
10131
*/
10132
10133
void GDALDataset::ClearStatistics()
10134
0
{
10135
0
    auto poRootGroup = GetRootGroup();
10136
0
    if (poRootGroup)
10137
0
        poRootGroup->ClearStatistics();
10138
0
}
10139
10140
/************************************************************************/
10141
/*                     GDALDatasetClearStatistics()                     */
10142
/************************************************************************/
10143
10144
/**
10145
 \brief Clear statistics
10146
10147
 This is the same as the C++ method GDALDataset::ClearStatistics().
10148
10149
 @since GDAL 3.2
10150
*/
10151
10152
void GDALDatasetClearStatistics(GDALDatasetH hDS)
10153
0
{
10154
0
    VALIDATE_POINTER0(hDS, __func__);
10155
0
    GDALDataset::FromHandle(hDS)->ClearStatistics();
10156
0
}
10157
10158
/************************************************************************/
10159
/*                        GetFieldDomainNames()                         */
10160
/************************************************************************/
10161
10162
/** Returns a list of the names of all field domains stored in the dataset.
10163
 *
10164
 * @note The default implementation assumes that drivers fully populate
10165
 * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10166
 * then a specialized implementation of GetFieldDomainNames() must be
10167
 * implemented.
10168
 *
10169
 * @param papszOptions Driver specific options determining how attributes
10170
 * should be retrieved. Pass nullptr for default behavior.
10171
 *
10172
 * @return list of field domain names
10173
 * @since GDAL 3.5
10174
 */
10175
std::vector<std::string>
10176
GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10177
0
{
10178
10179
0
    std::vector<std::string> names;
10180
0
    names.reserve(m_oMapFieldDomains.size());
10181
0
    for (const auto &it : m_oMapFieldDomains)
10182
0
    {
10183
0
        names.emplace_back(it.first);
10184
0
    }
10185
0
    return names;
10186
0
}
10187
10188
/************************************************************************/
10189
/*                   GDALDatasetGetFieldDomainNames()                   */
10190
/************************************************************************/
10191
10192
/** Returns a list of the names of all field domains stored in the dataset.
10193
 *
10194
 * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10195
 *
10196
 * @param hDS Dataset handle.
10197
 * @param papszOptions Driver specific options determining how attributes
10198
 * should be retrieved. Pass nullptr for default behavior.
10199
 *
10200
 * @return list of field domain names, to be freed with CSLDestroy()
10201
 * @since GDAL 3.5
10202
 */
10203
char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10204
                                      CSLConstList papszOptions)
10205
0
{
10206
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10207
0
    auto names =
10208
0
        GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10209
0
    CPLStringList res;
10210
0
    for (const auto &name : names)
10211
0
    {
10212
0
        res.AddString(name.c_str());
10213
0
    }
10214
0
    return res.StealList();
10215
0
}
10216
10217
/************************************************************************/
10218
/*                           GetFieldDomain()                           */
10219
/************************************************************************/
10220
10221
/** Get a field domain from its name.
10222
 *
10223
 * @return the field domain, or nullptr if not found.
10224
 * @since GDAL 3.3
10225
 */
10226
const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10227
0
{
10228
0
    const auto iter = m_oMapFieldDomains.find(name);
10229
0
    if (iter == m_oMapFieldDomains.end())
10230
0
        return nullptr;
10231
0
    return iter->second.get();
10232
0
}
10233
10234
/************************************************************************/
10235
/*                     GDALDatasetGetFieldDomain()                      */
10236
/************************************************************************/
10237
10238
/** Get a field domain from its name.
10239
 *
10240
 * This is the same as the C++ method GDALDataset::GetFieldDomain().
10241
 *
10242
 * @param hDS Dataset handle.
10243
 * @param pszName Name of field domain.
10244
 * @return the field domain (ownership remains to the dataset), or nullptr if
10245
 * not found.
10246
 * @since GDAL 3.3
10247
 */
10248
OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10249
0
{
10250
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10251
0
    VALIDATE_POINTER1(pszName, __func__, nullptr);
10252
0
    return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10253
0
        GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10254
0
}
10255
10256
/************************************************************************/
10257
/*                           AddFieldDomain()                           */
10258
/************************************************************************/
10259
10260
/** Add a field domain to the dataset.
10261
 *
10262
 * Only a few drivers will support this operation, and some of them might only
10263
 * support it only for some types of field domains.
10264
 * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10265
 * support this operation. A dataset having at least some support for this
10266
 * operation should report the ODsCAddFieldDomain dataset capability.
10267
 *
10268
 * Anticipated failures will not be emitted through the CPLError()
10269
 * infrastructure, but will be reported in the failureReason output parameter.
10270
 *
10271
 * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10272
 * default implementation of GetFieldDomainNames() to work correctly, or
10273
 * alternatively a specialized implementation of GetFieldDomainNames() should be
10274
 * implemented.
10275
 *
10276
 * @param domain The domain definition.
10277
 * @param failureReason      Output parameter. Will contain an error message if
10278
 *                           an error occurs.
10279
 * @return true in case of success.
10280
 * @since GDAL 3.3
10281
 */
10282
bool GDALDataset::AddFieldDomain(
10283
    CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10284
    std::string &failureReason)
10285
0
{
10286
0
    failureReason = "AddFieldDomain not supported by this driver";
10287
0
    return false;
10288
0
}
10289
10290
/************************************************************************/
10291
/*                     GDALDatasetAddFieldDomain()                      */
10292
/************************************************************************/
10293
10294
/** Add a field domain to the dataset.
10295
 *
10296
 * Only a few drivers will support this operation, and some of them might only
10297
 * support it only for some types of field domains.
10298
 * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10299
 * support this operation. A dataset having at least some support for this
10300
 * operation should report the ODsCAddFieldDomain dataset capability.
10301
 *
10302
 * Anticipated failures will not be emitted through the CPLError()
10303
 * infrastructure, but will be reported in the ppszFailureReason output
10304
 * parameter.
10305
 *
10306
 * @param hDS                Dataset handle.
10307
 * @param hFieldDomain       The domain definition. Contrary to the C++ version,
10308
 *                           the passed object is copied.
10309
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10310
 *                           an error occurs (*ppszFailureReason to be freed
10311
 *                           with CPLFree). May be NULL.
10312
 * @return true in case of success.
10313
 * @since GDAL 3.3
10314
 */
10315
bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10316
                               char **ppszFailureReason)
10317
0
{
10318
0
    VALIDATE_POINTER1(hDS, __func__, false);
10319
0
    VALIDATE_POINTER1(hFieldDomain, __func__, false);
10320
0
    auto poDomain = std::unique_ptr<OGRFieldDomain>(
10321
0
        OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10322
0
    if (poDomain == nullptr)
10323
0
        return false;
10324
0
    std::string failureReason;
10325
0
    const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10326
0
        std::move(poDomain), failureReason);
10327
0
    if (ppszFailureReason)
10328
0
    {
10329
0
        *ppszFailureReason =
10330
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10331
0
    }
10332
0
    return bRet;
10333
0
}
10334
10335
/************************************************************************/
10336
/*                         DeleteFieldDomain()                          */
10337
/************************************************************************/
10338
10339
/** Removes a field domain from the dataset.
10340
 *
10341
 * Only a few drivers will support this operation.
10342
 *
10343
 * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10344
 * support this operation. A dataset having at least some support for this
10345
 * operation should report the ODsCDeleteFieldDomain dataset capability.
10346
 *
10347
 * Anticipated failures will not be emitted through the CPLError()
10348
 * infrastructure, but will be reported in the failureReason output parameter.
10349
 *
10350
 * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10351
 * default implementation of GetFieldDomainNames() to work correctly, or
10352
 * alternatively a specialized implementation of GetFieldDomainNames() should be
10353
 * implemented.
10354
 *
10355
 * @param name The domain name.
10356
 * @param failureReason      Output parameter. Will contain an error message if
10357
 *                           an error occurs.
10358
 * @return true in case of success.
10359
 * @since GDAL 3.5
10360
 */
10361
bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10362
                                    std::string &failureReason)
10363
0
{
10364
0
    failureReason = "DeleteFieldDomain not supported by this driver";
10365
0
    return false;
10366
0
}
10367
10368
/************************************************************************/
10369
/*                    GDALDatasetDeleteFieldDomain()                    */
10370
/************************************************************************/
10371
10372
/** Removes a field domain from the dataset.
10373
 *
10374
 * Only a few drivers will support this operation.
10375
 *
10376
 * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10377
 * support this operation. A dataset having at least some support for this
10378
 * operation should report the ODsCDeleteFieldDomain dataset capability.
10379
 *
10380
 * Anticipated failures will not be emitted through the CPLError()
10381
 * infrastructure, but will be reported in the ppszFailureReason output
10382
 * parameter.
10383
 *
10384
 * @param hDS                Dataset handle.
10385
 * @param pszName            The domain name.
10386
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10387
 *                           an error occurs (*ppszFailureReason to be freed
10388
 *                           with CPLFree). May be NULL.
10389
 * @return true in case of success.
10390
 * @since GDAL 3.3
10391
 */
10392
bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10393
                                  char **ppszFailureReason)
10394
0
{
10395
0
    VALIDATE_POINTER1(hDS, __func__, false);
10396
0
    VALIDATE_POINTER1(pszName, __func__, false);
10397
0
    std::string failureReason;
10398
0
    const bool bRet =
10399
0
        GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10400
0
    if (ppszFailureReason)
10401
0
    {
10402
0
        *ppszFailureReason =
10403
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10404
0
    }
10405
0
    return bRet;
10406
0
}
10407
10408
/************************************************************************/
10409
/*                         UpdateFieldDomain()                          */
10410
/************************************************************************/
10411
10412
/** Updates an existing field domain by replacing its definition.
10413
 *
10414
 * The existing field domain with matching name will be replaced.
10415
 *
10416
 * Only a few drivers will support this operation, and some of them might only
10417
 * support it only for some types of field domains.
10418
 * At the time of writing (GDAL 3.5), only the Memory driver
10419
 * supports this operation. A dataset having at least some support for this
10420
 * operation should report the ODsCUpdateFieldDomain dataset capability.
10421
 *
10422
 * Anticipated failures will not be emitted through the CPLError()
10423
 * infrastructure, but will be reported in the failureReason output parameter.
10424
 *
10425
 * @param domain The domain definition.
10426
 * @param failureReason      Output parameter. Will contain an error message if
10427
 *                           an error occurs.
10428
 * @return true in case of success.
10429
 * @since GDAL 3.5
10430
 */
10431
bool GDALDataset::UpdateFieldDomain(
10432
    CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10433
    std::string &failureReason)
10434
0
{
10435
0
    failureReason = "UpdateFieldDomain not supported by this driver";
10436
0
    return false;
10437
0
}
10438
10439
/************************************************************************/
10440
/*                    GDALDatasetUpdateFieldDomain()                    */
10441
/************************************************************************/
10442
10443
/** Updates an existing field domain by replacing its definition.
10444
 *
10445
 * The existing field domain with matching name will be replaced.
10446
 *
10447
 * Only a few drivers will support this operation, and some of them might only
10448
 * support it only for some types of field domains.
10449
 * At the time of writing (GDAL 3.5), only the Memory driver
10450
 * supports this operation. A dataset having at least some support for this
10451
 * operation should report the ODsCUpdateFieldDomain dataset capability.
10452
 *
10453
 * Anticipated failures will not be emitted through the CPLError()
10454
 * infrastructure, but will be reported in the failureReason output parameter.
10455
 *
10456
 * @param hDS                Dataset handle.
10457
 * @param hFieldDomain       The domain definition. Contrary to the C++ version,
10458
 *                           the passed object is copied.
10459
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10460
 *                           an error occurs (*ppszFailureReason to be freed
10461
 *                           with CPLFree). May be NULL.
10462
 * @return true in case of success.
10463
 * @since GDAL 3.5
10464
 */
10465
bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10466
                                  OGRFieldDomainH hFieldDomain,
10467
                                  char **ppszFailureReason)
10468
0
{
10469
0
    VALIDATE_POINTER1(hDS, __func__, false);
10470
0
    VALIDATE_POINTER1(hFieldDomain, __func__, false);
10471
0
    auto poDomain = std::unique_ptr<OGRFieldDomain>(
10472
0
        OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10473
0
    if (poDomain == nullptr)
10474
0
        return false;
10475
0
    std::string failureReason;
10476
0
    const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10477
0
        std::move(poDomain), failureReason);
10478
0
    if (ppszFailureReason)
10479
0
    {
10480
0
        *ppszFailureReason =
10481
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10482
0
    }
10483
0
    return bRet;
10484
0
}
10485
10486
/************************************************************************/
10487
/*                        GetRelationshipNames()                        */
10488
/************************************************************************/
10489
10490
/** Returns a list of the names of all relationships stored in the dataset.
10491
 *
10492
 * @param papszOptions Driver specific options determining how relationships
10493
 * should be retrieved. Pass nullptr for default behavior.
10494
 *
10495
 * @return list of relationship names
10496
 * @since GDAL 3.6
10497
 */
10498
std::vector<std::string>
10499
GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10500
0
{
10501
0
    return {};
10502
0
}
10503
10504
/************************************************************************/
10505
/*                  GDALDatasetGetRelationshipNames()                   */
10506
/************************************************************************/
10507
10508
/** Returns a list of the names of all relationships stored in the dataset.
10509
 *
10510
 * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10511
 *
10512
 * @param hDS Dataset handle.
10513
 * @param papszOptions Driver specific options determining how relationships
10514
 * should be retrieved. Pass nullptr for default behavior.
10515
 *
10516
 * @return list of relationship names, to be freed with CSLDestroy()
10517
 * @since GDAL 3.6
10518
 */
10519
char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10520
                                       CSLConstList papszOptions)
10521
0
{
10522
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10523
0
    auto names =
10524
0
        GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10525
0
    CPLStringList res;
10526
0
    for (const auto &name : names)
10527
0
    {
10528
0
        res.AddString(name.c_str());
10529
0
    }
10530
0
    return res.StealList();
10531
0
}
10532
10533
/************************************************************************/
10534
/*                          GetRelationship()                           */
10535
/************************************************************************/
10536
10537
/** Get a relationship from its name.
10538
 *
10539
 * @return the relationship, or nullptr if not found.
10540
 * @since GDAL 3.6
10541
 */
10542
const GDALRelationship *
10543
GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10544
0
{
10545
0
    return nullptr;
10546
0
}
10547
10548
/************************************************************************/
10549
/*                     GDALDatasetGetRelationship()                     */
10550
/************************************************************************/
10551
10552
/** Get a relationship from its name.
10553
 *
10554
 * This is the same as the C++ method GDALDataset::GetRelationship().
10555
 *
10556
 * @param hDS Dataset handle.
10557
 * @param pszName Name of relationship.
10558
 * @return the relationship (ownership remains to the dataset), or nullptr if
10559
 * not found.
10560
 * @since GDAL 3.6
10561
 */
10562
GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10563
                                             const char *pszName)
10564
0
{
10565
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10566
0
    VALIDATE_POINTER1(pszName, __func__, nullptr);
10567
0
    return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10568
0
        GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10569
0
}
10570
10571
/************************************************************************/
10572
/*                          AddRelationship()                           */
10573
/************************************************************************/
10574
10575
/** Add a relationship to the dataset.
10576
 *
10577
 * Only a few drivers will support this operation, and some of them might only
10578
 * support it only for some types of relationships.
10579
 *
10580
 * A dataset having at least some support for this
10581
 * operation should report the GDsCAddRelationship dataset capability.
10582
 *
10583
 * Anticipated failures will not be emitted through the CPLError()
10584
 * infrastructure, but will be reported in the failureReason output parameter.
10585
 *
10586
 * When adding a many-to-many relationship
10587
 * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10588
 * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10589
 * the driver to create an appropriately named and structured mapping table.
10590
 * Some dataset formats require particular naming conventions and field
10591
 * structures for the mapping table, and delegating the construction of the
10592
 * mapping table to the driver will avoid these pitfalls.
10593
 *
10594
 * @param relationship The relationship definition.
10595
 * @param failureReason      Output parameter. Will contain an error message if
10596
 *                           an error occurs.
10597
 * @return true in case of success.
10598
 * @since GDAL 3.6
10599
 */
10600
bool GDALDataset::AddRelationship(
10601
    CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10602
    std::string &failureReason)
10603
0
{
10604
0
    failureReason = "AddRelationship not supported by this driver";
10605
0
    return false;
10606
0
}
10607
10608
/************************************************************************/
10609
/*                     GDALDatasetAddRelationship()                     */
10610
/************************************************************************/
10611
10612
/** Add a relationship to the dataset.
10613
 *
10614
 * Only a few drivers will support this operation, and some of them might only
10615
 * support it only for some types of relationships.
10616
 *
10617
 * A dataset having at least some support for this
10618
 * operation should report the GDsCAddRelationship dataset capability.
10619
 *
10620
 * Anticipated failures will not be emitted through the CPLError()
10621
 * infrastructure, but will be reported in the failureReason output parameter.
10622
 *
10623
 * When adding a many-to-many relationship
10624
 * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10625
 * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10626
 * driver to create an appropriately named and structured mapping table. Some
10627
 * dataset formats require particular naming conventions and field structures
10628
 * for the mapping table, and delegating the construction of the mapping table
10629
 * to the driver will avoid these pitfalls.
10630
 *
10631
 * @param hDS                Dataset handle.
10632
 * @param hRelationship      The relationship definition. Contrary to the C++
10633
 * version, the passed object is copied.
10634
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10635
 *                           an error occurs (*ppszFailureReason to be freed
10636
 *                           with CPLFree). May be NULL.
10637
 * @return true in case of success.
10638
 * @since GDAL 3.6
10639
 */
10640
bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10641
                                GDALRelationshipH hRelationship,
10642
                                char **ppszFailureReason)
10643
0
{
10644
0
    VALIDATE_POINTER1(hDS, __func__, false);
10645
0
    VALIDATE_POINTER1(hRelationship, __func__, false);
10646
0
    std::unique_ptr<GDALRelationship> poRelationship(
10647
0
        new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10648
0
    std::string failureReason;
10649
0
    const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10650
0
        std::move(poRelationship), failureReason);
10651
0
    if (ppszFailureReason)
10652
0
    {
10653
0
        *ppszFailureReason =
10654
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10655
0
    }
10656
0
    return bRet;
10657
0
}
10658
10659
/************************************************************************/
10660
/*                         DeleteRelationship()                         */
10661
/************************************************************************/
10662
10663
/** Removes a relationship from the dataset.
10664
 *
10665
 * Only a few drivers will support this operation.
10666
 *
10667
 * A dataset having at least some support for this
10668
 * operation should report the GDsCDeleteRelationship dataset capability.
10669
 *
10670
 * Anticipated failures will not be emitted through the CPLError()
10671
 * infrastructure, but will be reported in the failureReason output parameter.
10672
 *
10673
 * @param name The relationship name.
10674
 * @param failureReason      Output parameter. Will contain an error message if
10675
 *                           an error occurs.
10676
 * @return true in case of success.
10677
 * @since GDAL 3.6
10678
 */
10679
bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10680
                                     std::string &failureReason)
10681
0
{
10682
0
    failureReason = "DeleteRelationship not supported by this driver";
10683
0
    return false;
10684
0
}
10685
10686
/************************************************************************/
10687
/*                   GDALDatasetDeleteRelationship()                    */
10688
/************************************************************************/
10689
10690
/** Removes a relationship from the dataset.
10691
 *
10692
 * Only a few drivers will support this operation.
10693
 *
10694
 * A dataset having at least some support for this
10695
 * operation should report the GDsCDeleteRelationship dataset capability.
10696
 *
10697
 * Anticipated failures will not be emitted through the CPLError()
10698
 * infrastructure, but will be reported in the ppszFailureReason output
10699
 * parameter.
10700
 *
10701
 * @param hDS                Dataset handle.
10702
 * @param pszName            The relationship name.
10703
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10704
 *                           an error occurs (*ppszFailureReason to be freed
10705
 *                           with CPLFree). May be NULL.
10706
 * @return true in case of success.
10707
 * @since GDAL 3.6
10708
 */
10709
bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10710
                                   char **ppszFailureReason)
10711
0
{
10712
0
    VALIDATE_POINTER1(hDS, __func__, false);
10713
0
    VALIDATE_POINTER1(pszName, __func__, false);
10714
0
    std::string failureReason;
10715
0
    const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10716
0
        pszName, failureReason);
10717
0
    if (ppszFailureReason)
10718
0
    {
10719
0
        *ppszFailureReason =
10720
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10721
0
    }
10722
0
    return bRet;
10723
0
}
10724
10725
/************************************************************************/
10726
/*                         UpdateRelationship()                         */
10727
/************************************************************************/
10728
10729
/** Updates an existing relationship by replacing its definition.
10730
 *
10731
 * The existing relationship with matching name will be replaced.
10732
 *
10733
 * Only a few drivers will support this operation, and some of them might only
10734
 * support it only for some types of relationships.
10735
 * A dataset having at least some support for this
10736
 * operation should report the GDsCUpdateRelationship dataset capability.
10737
 *
10738
 * Anticipated failures will not be emitted through the CPLError()
10739
 * infrastructure, but will be reported in the failureReason output parameter.
10740
 *
10741
 * @param relationship   The relationship definition.
10742
 * @param failureReason  Output parameter. Will contain an error message if
10743
 *                       an error occurs.
10744
 * @return true in case of success.
10745
 * @since GDAL 3.6
10746
 */
10747
bool GDALDataset::UpdateRelationship(
10748
    CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10749
    std::string &failureReason)
10750
0
{
10751
0
    failureReason = "UpdateRelationship not supported by this driver";
10752
0
    return false;
10753
0
}
10754
10755
/************************************************************************/
10756
/*                   GDALDatasetUpdateRelationship()                    */
10757
/************************************************************************/
10758
10759
/** Updates an existing relationship by replacing its definition.
10760
 *
10761
 * The existing relationship with matching name will be replaced.
10762
 *
10763
 * Only a few drivers will support this operation, and some of them might only
10764
 * support it only for some types of relationships.
10765
 * A dataset having at least some support for this
10766
 * operation should report the GDsCUpdateRelationship dataset capability.
10767
 *
10768
 * Anticipated failures will not be emitted through the CPLError()
10769
 * infrastructure, but will be reported in the failureReason output parameter.
10770
 *
10771
 * @param hDS                Dataset handle.
10772
 * @param hRelationship      The relationship definition. Contrary to the C++
10773
 * version, the passed object is copied.
10774
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10775
 *                           an error occurs (*ppszFailureReason to be freed
10776
 *                           with CPLFree). May be NULL.
10777
 * @return true in case of success.
10778
 * @since GDAL 3.5
10779
 */
10780
bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10781
                                   GDALRelationshipH hRelationship,
10782
                                   char **ppszFailureReason)
10783
0
{
10784
0
    VALIDATE_POINTER1(hDS, __func__, false);
10785
0
    VALIDATE_POINTER1(hRelationship, __func__, false);
10786
0
    std::unique_ptr<GDALRelationship> poRelationship(
10787
0
        new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10788
0
    std::string failureReason;
10789
0
    const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10790
0
        std::move(poRelationship), failureReason);
10791
0
    if (ppszFailureReason)
10792
0
    {
10793
0
        *ppszFailureReason =
10794
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10795
0
    }
10796
0
    return bRet;
10797
0
}
10798
10799
/************************************************************************/
10800
/*                   GDALDatasetSetQueryLoggerFunc()                    */
10801
/************************************************************************/
10802
10803
/**
10804
 * Sets the SQL query logger callback.
10805
 *
10806
 * When supported by the driver, the callback will be called with
10807
 * the executed SQL text, the error message, the execution time in milliseconds,
10808
 * the number of records fetched/affected and the client status data.
10809
 *
10810
 * A value of -1 in the execution time or in the number of records indicates
10811
 * that the values are unknown.
10812
 *
10813
 * @param hDS                   Dataset handle.
10814
 * @param pfnQueryLoggerFunc    Callback function
10815
 * @param poQueryLoggerArg      Opaque client status data
10816
 * @return                      true in case of success.
10817
 * @since                       GDAL 3.7
10818
 */
10819
bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10820
                                   GDALQueryLoggerFunc pfnQueryLoggerFunc,
10821
                                   void *poQueryLoggerArg)
10822
0
{
10823
0
    VALIDATE_POINTER1(hDS, __func__, false);
10824
0
    return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10825
0
                                                            poQueryLoggerArg);
10826
0
}
10827
10828
//! @cond Doxygen_Suppress
10829
10830
/************************************************************************/
10831
/*                         SetEnableOverviews()                         */
10832
/************************************************************************/
10833
10834
void GDALDataset::SetEnableOverviews(bool bEnable)
10835
0
{
10836
0
    if (m_poPrivate)
10837
0
    {
10838
0
        m_poPrivate->m_bOverviewsEnabled = bEnable;
10839
0
    }
10840
0
}
10841
10842
/************************************************************************/
10843
/*                        AreOverviewsEnabled()                         */
10844
/************************************************************************/
10845
10846
bool GDALDataset::AreOverviewsEnabled() const
10847
0
{
10848
0
    return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10849
0
}
10850
10851
/************************************************************************/
10852
/*                             IsAllBands()                             */
10853
/************************************************************************/
10854
10855
bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10856
0
{
10857
0
    if (nBands != nBandCount)
10858
0
        return false;
10859
0
    if (panBandList)
10860
0
    {
10861
0
        for (int i = 0; i < nBandCount; ++i)
10862
0
        {
10863
0
            if (panBandList[i] != i + 1)
10864
0
                return false;
10865
0
        }
10866
0
    }
10867
0
    return true;
10868
0
}
10869
10870
//! @endcond
10871
10872
/************************************************************************/
10873
/*                       GetCompressionFormats()                        */
10874
/************************************************************************/
10875
10876
/** Return the compression formats that can be natively obtained for the
10877
 * window of interest and requested bands.
10878
 *
10879
 * For example, a tiled dataset may be able to return data in a compressed
10880
 * format if the window of interest matches exactly a tile. For some formats,
10881
 * drivers may also be able to merge several tiles together (not currently
10882
 * implemented though).
10883
 *
10884
 * Each format string is a pseudo MIME type, whose first part can be passed
10885
 * as the pszFormat argument of ReadCompressedData(), with additional
10886
 * parameters specified as key=value with a semi-colon separator.
10887
 *
10888
 * The amount and types of optional parameters passed after the MIME type is
10889
 * format dependent, and driver dependent (some drivers might not be able to
10890
 * return those extra information without doing a rather costly processing).
10891
 *
10892
 * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10893
 * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10894
 * consequently "JPEG" can be passed as the pszFormat argument of
10895
 * ReadCompressedData(). For JPEG, implementations can use the
10896
 * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10897
 * above from a JPEG codestream.
10898
 *
10899
 * Several values might be returned. For example,
10900
 * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10901
 * if the JPEGXL codestream includes a JPEG reconstruction box.
10902
 *
10903
 * In the general case this method will return an empty list.
10904
 *
10905
 * This is the same as C function GDALDatasetGetCompressionFormats().
10906
 *
10907
 * @param nXOff The pixel offset to the top left corner of the region
10908
 * of the band to be accessed.  This would be zero to start from the left side.
10909
 *
10910
 * @param nYOff The line offset to the top left corner of the region
10911
 * of the band to be accessed.  This would be zero to start from the top.
10912
 *
10913
 * @param nXSize The width of the region of the band to be accessed in pixels.
10914
 *
10915
 * @param nYSize The height of the region of the band to be accessed in lines.
10916
 *
10917
 * @param nBandCount the number of bands being requested.
10918
 *
10919
 * @param panBandList the list of nBandCount band numbers.
10920
 * Note band numbers are 1 based. This may be NULL to select the first
10921
 * nBandCount bands.
10922
 *
10923
 * @return a list of compatible formats (which may be empty)
10924
 *
10925
 * For example, to check if native compression format(s) are available on the
10926
 * whole image:
10927
 * \code{.cpp}
10928
 *   const CPLStringList aosFormats =
10929
 *      poDataset->GetCompressionFormats(0, 0,
10930
 *                                       poDataset->GetRasterXSize(),
10931
 *                                       poDataset->GetRasterYSize(),
10932
 *                                       poDataset->GetRasterCount(),
10933
 *                                       nullptr);
10934
 *   for( const char* pszFormat: aosFormats )
10935
 *   {
10936
 *      // Remove optional parameters and just print out the MIME type.
10937
 *      const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10938
 *      printf("Found format %s\n, aosTokens[0]);
10939
 *   }
10940
 * \endcode
10941
 *
10942
 * @since GDAL 3.7
10943
 */
10944
CPLStringList
10945
GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10946
                                   CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10947
                                   CPL_UNUSED int nBandCount,
10948
                                   CPL_UNUSED const int *panBandList)
10949
0
{
10950
0
    return CPLStringList();
10951
0
}
10952
10953
/************************************************************************/
10954
/*                  GDALDatasetGetCompressionFormats()                  */
10955
/************************************************************************/
10956
10957
/** Return the compression formats that can be natively obtained for the
10958
 * window of interest and requested bands.
10959
 *
10960
 * For example, a tiled dataset may be able to return data in a compressed
10961
 * format if the window of interest matches exactly a tile. For some formats,
10962
 * drivers may also be able to merge several tiles together (not currently
10963
 * implemented though).
10964
 *
10965
 * Each format string is a pseudo MIME type, whose first part can be passed
10966
 * as the pszFormat argument of ReadCompressedData(), with additional
10967
 * parameters specified as key=value with a semi-colon separator.
10968
 *
10969
 * The amount and types of optional parameters passed after the MIME type is
10970
 * format dependent, and driver dependent (some drivers might not be able to
10971
 * return those extra information without doing a rather costly processing).
10972
 *
10973
 * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10974
 * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10975
 * consequently "JPEG" can be passed as the pszFormat argument of
10976
 * ReadCompressedData(). For JPEG, implementations can use the
10977
 * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10978
 * above from a JPEG codestream.
10979
 *
10980
 * Several values might be returned. For example,
10981
 * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10982
 * if the JPEGXL codestream includes a JPEG reconstruction box.
10983
 *
10984
 * In the general case this method will return an empty list.
10985
 *
10986
 * This is the same as C++ method GDALDataset::GetCompressionFormats().
10987
 *
10988
 * @param hDS Dataset handle.
10989
 *
10990
 * @param nXOff The pixel offset to the top left corner of the region
10991
 * of the band to be accessed.  This would be zero to start from the left side.
10992
 *
10993
 * @param nYOff The line offset to the top left corner of the region
10994
 * of the band to be accessed.  This would be zero to start from the top.
10995
 *
10996
 * @param nXSize The width of the region of the band to be accessed in pixels.
10997
 *
10998
 * @param nYSize The height of the region of the band to be accessed in lines.
10999
 *
11000
 * @param nBandCount the number of bands being requested.
11001
 *
11002
 * @param panBandList the list of nBandCount band numbers.
11003
 * Note band numbers are 1 based. This may be NULL to select the first
11004
 * nBandCount bands.
11005
 *
11006
 * @return a list of compatible formats (which may be empty) that should be
11007
 * freed with CSLDestroy(), or nullptr.
11008
 *
11009
 * @since GDAL 3.7
11010
 */
11011
char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
11012
                                        int nXSize, int nYSize, int nBandCount,
11013
                                        const int *panBandList)
11014
0
{
11015
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
11016
0
    return GDALDataset::FromHandle(hDS)
11017
0
        ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
11018
0
                                panBandList)
11019
0
        .StealList();
11020
0
}
11021
11022
/************************************************************************/
11023
/*                         ReadCompressedData()                         */
11024
/************************************************************************/
11025
11026
/** Return the compressed content that can be natively obtained for the
11027
 * window of interest and requested bands.
11028
 *
11029
 * For example, a tiled dataset may be able to return data in compressed format
11030
 * if the window of interest matches exactly a tile. For some formats, drivers
11031
 * may also be example to merge several tiles together (not currently
11032
 * implemented though).
11033
 *
11034
 * The implementation should make sure that the content returned forms a valid
11035
 * standalone file. For example, for the GeoTIFF implementation of this method,
11036
 * when extracting a JPEG tile, the method will automatically add the content
11037
 * of the JPEG Huffman and/or quantization tables that might be stored in the
11038
 * TIFF JpegTables tag, and not in tile data itself.
11039
 *
11040
 * In the general case this method will return CE_Failure.
11041
 *
11042
 * This is the same as C function GDALDatasetReadCompressedData().
11043
 *
11044
 * @param pszFormat Requested compression format (e.g. "JPEG",
11045
 * "WEBP", "JXL"). This is the MIME type of one of the values
11046
 * returned by GetCompressionFormats(). The format string is designed to
11047
 * potentially include at a later point key=value optional parameters separated
11048
 * by a semi-colon character. At time of writing, none are implemented.
11049
 * ReadCompressedData() implementations should verify optional parameters and
11050
 * return CE_Failure if they cannot support one of them.
11051
 *
11052
 * @param nXOff The pixel offset to the top left corner of the region
11053
 * of the band to be accessed.  This would be zero to start from the left side.
11054
 *
11055
 * @param nYOff The line offset to the top left corner of the region
11056
 * of the band to be accessed.  This would be zero to start from the top.
11057
 *
11058
 * @param nXSize The width of the region of the band to be accessed in pixels.
11059
 *
11060
 * @param nYSize The height of the region of the band to be accessed in lines.
11061
 *
11062
 * @param nBandCount the number of bands being requested.
11063
 *
11064
 * @param panBandList the list of nBandCount band numbers.
11065
 * Note band numbers are 1 based. This may be NULL to select the first
11066
 * nBandCount bands.
11067
 *
11068
 * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11069
 * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11070
 * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11071
 * buffer will be filled with the compressed data, provided that pnBufferSize
11072
 * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11073
 * of *ppBuffer, is sufficiently large to hold the data.
11074
 * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11075
 * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11076
 * free it with VSIFree().
11077
 * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11078
 * but *pnBufferSize will be updated with an upper bound of the size that would
11079
 * be necessary to hold it (if pnBufferSize != nullptr).
11080
 *
11081
 * @param pnBufferSize Output buffer size, or nullptr.
11082
 * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11083
 * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11084
 * method is successful, *pnBufferSize will be updated with the actual size
11085
 * used.
11086
 *
11087
 * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11088
 * If ppszDetailedFormat is not nullptr, then, on success, the method will
11089
 * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11090
 * *ppszDetailedFormat might contain strings like
11091
 * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11092
 * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11093
 * The string will contain at least as much information as what
11094
 * GetCompressionFormats() returns, and potentially more when
11095
 * ppBuffer != nullptr.
11096
 *
11097
 * @return CE_None in case of success, CE_Failure otherwise.
11098
 *
11099
 * For example, to request JPEG content on the whole image and let GDAL deal
11100
 * with the buffer allocation.
11101
 * \code{.cpp}
11102
 *   void* pBuffer = nullptr;
11103
 *   size_t nBufferSize = 0;
11104
 *   CPLErr eErr =
11105
 *      poDataset->ReadCompressedData("JPEG",
11106
 *                                    0, 0,
11107
 *                                    poDataset->GetRasterXSize(),
11108
 *                                    poDataset->GetRasterYSize(),
11109
 *                                    poDataset->GetRasterCount(),
11110
 *                                    nullptr, // panBandList
11111
 *                                    &pBuffer,
11112
 *                                    &nBufferSize,
11113
 *                                    nullptr // ppszDetailedFormat
11114
 *                                   );
11115
 *   if (eErr == CE_None)
11116
 *   {
11117
 *       CPLAssert(pBuffer != nullptr);
11118
 *       CPLAssert(nBufferSize > 0);
11119
 *       VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11120
 *       if (fp)
11121
 *       {
11122
 *           VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11123
 *           VSIFCloseL(fp);
11124
 *       }
11125
 *       VSIFree(pBuffer);
11126
 *   }
11127
 * \endcode
11128
 *
11129
 * Or to manage the buffer allocation on your side:
11130
 * \code{.cpp}
11131
 *   size_t nUpperBoundBufferSize = 0;
11132
 *   CPLErr eErr =
11133
 *      poDataset->ReadCompressedData("JPEG",
11134
 *                                    0, 0,
11135
 *                                    poDataset->GetRasterXSize(),
11136
 *                                    poDataset->GetRasterYSize(),
11137
 *                                    poDataset->GetRasterCount(),
11138
 *                                    nullptr, // panBandList
11139
 *                                    nullptr, // ppBuffer,
11140
 *                                    &nUpperBoundBufferSize,
11141
 *                                    nullptr // ppszDetailedFormat
11142
 *                                   );
11143
 *   if (eErr == CE_None)
11144
 *   {
11145
 *       std::vector<uint8_t> myBuffer;
11146
 *       myBuffer.resize(nUpperBoundBufferSize);
11147
 *       void* pBuffer = myBuffer.data();
11148
 *       size_t nActualSize = nUpperBoundBufferSize;
11149
 *       char* pszDetailedFormat = nullptr;
11150
 *       // We also request detailed format, but we could have passed it to
11151
 *       // nullptr as well.
11152
 *       eErr =
11153
 *         poDataset->ReadCompressedData("JPEG",
11154
 *                                       0, 0,
11155
 *                                       poDataset->GetRasterXSize(),
11156
 *                                       poDataset->GetRasterYSize(),
11157
 *                                       poDataset->GetRasterCount(),
11158
 *                                       nullptr, // panBandList
11159
 *                                       &pBuffer,
11160
 *                                       &nActualSize,
11161
 *                                       &pszDetailedFormat);
11162
 *       if (eErr == CE_None)
11163
 *       {
11164
 *          CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11165
 *          CPLAssert(nActualSize <= nUpperBoundBufferSize);
11166
 *          myBuffer.resize(nActualSize);
11167
 *          // do something useful
11168
 *          VSIFree(pszDetailedFormat);
11169
 *       }
11170
 *   }
11171
 * \endcode
11172
 *
11173
 * @since GDAL 3.7
11174
 */
11175
CPLErr GDALDataset::ReadCompressedData(
11176
    CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11177
    CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11178
    CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11179
    CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11180
    CPL_UNUSED char **ppszDetailedFormat)
11181
0
{
11182
0
    return CE_Failure;
11183
0
}
11184
11185
/************************************************************************/
11186
/*                   GDALDatasetReadCompressedData()                    */
11187
/************************************************************************/
11188
11189
/** Return the compressed content that can be natively obtained for the
11190
 * window of interest and requested bands.
11191
 *
11192
 * For example, a tiled dataset may be able to return data in compressed format
11193
 * if the window of interest matches exactly a tile. For some formats, drivers
11194
 * may also be example to merge several tiles together (not currently
11195
 * implemented though).
11196
 *
11197
 * The implementation should make sure that the content returned forms a valid
11198
 * standalone file. For example, for the GeoTIFF implementation of this method,
11199
 * when extracting a JPEG tile, the method will automatically adds the content
11200
 * of the JPEG Huffman and/or quantization tables that might be stored in the
11201
 * TIFF JpegTables tag, and not in tile data itself.
11202
 *
11203
 * In the general case this method will return CE_Failure.
11204
 *
11205
 * This is the same as C++ method GDALDataset:ReadCompressedData().
11206
 *
11207
 * @param hDS Dataset handle.
11208
 *
11209
 * @param pszFormat Requested compression format (e.g. "JPEG",
11210
 * "WEBP", "JXL"). This is the MIME type of one of the values
11211
 * returned by GetCompressionFormats(). The format string is designed to
11212
 * potentially include at a later point key=value optional parameters separated
11213
 * by a semi-colon character. At time of writing, none are implemented.
11214
 * ReadCompressedData() implementations should verify optional parameters and
11215
 * return CE_Failure if they cannot support one of them.
11216
 *
11217
 * @param nXOff The pixel offset to the top left corner of the region
11218
 * of the band to be accessed.  This would be zero to start from the left side.
11219
 *
11220
 * @param nYOff The line offset to the top left corner of the region
11221
 * of the band to be accessed.  This would be zero to start from the top.
11222
 *
11223
 * @param nXSize The width of the region of the band to be accessed in pixels.
11224
 *
11225
 * @param nYSize The height of the region of the band to be accessed in lines.
11226
 *
11227
 * @param nBandCount the number of bands being requested.
11228
 *
11229
 * @param panBandList the list of nBandCount band numbers.
11230
 * Note band numbers are 1 based. This may be NULL to select the first
11231
 * nBandCount bands.
11232
 *
11233
 * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11234
 * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11235
 * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11236
 * buffer will be filled with the compressed data, provided that pnBufferSize
11237
 * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11238
 * of *ppBuffer, is sufficiently large to hold the data.
11239
 * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11240
 * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11241
 * free it with VSIFree().
11242
 * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11243
 * but *pnBufferSize will be updated with an upper bound of the size that would
11244
 * be necessary to hold it (if pnBufferSize != nullptr).
11245
 *
11246
 * @param pnBufferSize Output buffer size, or nullptr.
11247
 * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11248
 * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11249
 * method is successful, *pnBufferSize will be updated with the actual size
11250
 * used.
11251
 *
11252
 * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11253
 * If ppszDetailedFormat is not nullptr, then, on success, the method will
11254
 * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11255
 * *ppszDetailedFormat might contain strings like
11256
 * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11257
 * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11258
 * The string will contain at least as much information as what
11259
 * GetCompressionFormats() returns, and potentially more when
11260
 * ppBuffer != nullptr.
11261
 *
11262
 * @return CE_None in case of success, CE_Failure otherwise.
11263
 *
11264
 * @since GDAL 3.7
11265
 */
11266
CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11267
                                     int nXOff, int nYOff, int nXSize,
11268
                                     int nYSize, int nBandCount,
11269
                                     const int *panBandList, void **ppBuffer,
11270
                                     size_t *pnBufferSize,
11271
                                     char **ppszDetailedFormat)
11272
0
{
11273
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11274
0
    return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11275
0
        pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11276
0
        ppBuffer, pnBufferSize, ppszDetailedFormat);
11277
0
}
11278
11279
/************************************************************************/
11280
/*                            CanBeCloned()                             */
11281
/************************************************************************/
11282
11283
//! @cond Doxygen_Suppress
11284
11285
/** This method is called by GDALThreadSafeDataset::Create() to determine if
11286
 * it is possible to create a thread-safe wrapper for a dataset, which involves
11287
 * the ability to Clone() it.
11288
 *
11289
 * Implementations of this method must be thread-safe.
11290
 *
11291
 * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11292
 *                    expressing the intended use for thread-safety.
11293
 *                    Currently, the only valid scope is in the base
11294
 *                    implementation is GDAL_OF_RASTER.
11295
 * @param bCanShareState Determines if cloned datasets are allowed to share
11296
 *                       state with the dataset they have been cloned from.
11297
 *                       If set to true, the dataset from which they have been
11298
 *                       cloned from must remain opened during the lifetime of
11299
 *                       its clones.
11300
 * @return true if the Clone() method is expected to succeed with the same values
11301
 *         of nScopeFlags and bCanShareState.
11302
 */
11303
bool GDALDataset::CanBeCloned(int nScopeFlags,
11304
                              [[maybe_unused]] bool bCanShareState) const
11305
0
{
11306
0
    return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11307
0
}
11308
11309
//! @endcond
11310
11311
/************************************************************************/
11312
/*                               Clone()                                */
11313
/************************************************************************/
11314
11315
//! @cond Doxygen_Suppress
11316
11317
/** This method "clones" the current dataset, that is it returns a new instance
11318
 * that is opened on the same underlying "file".
11319
 *
11320
 * The base implementation uses GDALDataset::Open() to re-open the dataset.
11321
 * The MEM driver has a specialized implementation that returns a new instance,
11322
 * but which shares the same memory buffer as this.
11323
 *
11324
 * Implementations of this method must be thread-safe.
11325
 *
11326
 * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11327
 *                    expressing the intended use for thread-safety.
11328
 *                    Currently, the only valid scope is in the base
11329
 *                    implementation is GDAL_OF_RASTER.
11330
 * @param bCanShareState Determines if cloned datasets are allowed to share
11331
 *                       state with the dataset they have been cloned from.
11332
 *                       If set to true, the dataset from which they have been
11333
 *                       cloned from must remain opened during the lifetime of
11334
 *                       its clones.
11335
 * @return a new instance, or nullptr in case of error.
11336
 */
11337
std::unique_ptr<GDALDataset>
11338
GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11339
0
{
11340
0
    CPLStringList aosAllowedDrivers;
11341
0
    if (poDriver)
11342
0
        aosAllowedDrivers.AddString(poDriver->GetDescription());
11343
0
    return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11344
0
        GetDescription(),
11345
0
        nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11346
0
        aosAllowedDrivers.List(), papszOpenOptions));
11347
0
}
11348
11349
//! @endcond
11350
11351
/************************************************************************/
11352
/*                       GeolocationToPixelLine()                       */
11353
/************************************************************************/
11354
11355
/** Transform georeferenced coordinates to pixel/line coordinates.
11356
 *
11357
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11358
 * must be in the "natural" SRS of the dataset, that is the one returned by
11359
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11360
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11361
 * array (generally WGS 84) if there is a geolocation array.
11362
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11363
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11364
 * be a easting, and dfGeolocY a northing.
11365
 *
11366
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11367
 * expressed in that CRS, and that tuple must be conformant with the
11368
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11369
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11370
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11371
 * before calling this method, and in that case, dfGeolocX must be a longitude
11372
 * or an easting value, and dfGeolocX a latitude or a northing value.
11373
 *
11374
 * This method uses GDALCreateGenImgProjTransformer2() underneath.
11375
 *
11376
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11377
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11378
 * where interpolation should be done.
11379
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11380
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11381
 * where interpolation should be done.
11382
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11383
 * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11384
 * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11385
 * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11386
 *
11387
 * @return CE_None on success, or an error code on failure.
11388
 * @since GDAL 3.11
11389
 */
11390
11391
CPLErr
11392
GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11393
                                    const OGRSpatialReference *poSRS,
11394
                                    double *pdfPixel, double *pdfLine,
11395
                                    CSLConstList papszTransformerOptions) const
11396
0
{
11397
0
    CPLStringList aosTO(papszTransformerOptions);
11398
11399
0
    if (poSRS)
11400
0
    {
11401
0
        const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11402
0
        const std::string osWKT = poSRS->exportToWkt(apszOptions);
11403
0
        aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11404
0
        const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11405
0
        if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11406
0
            aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11407
0
                               "TRADITIONAL_GIS_ORDER");
11408
0
        else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11409
0
            aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11410
0
                               "AUTHORITY_COMPLIANT");
11411
0
        else
11412
0
        {
11413
0
            const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11414
0
            std::string osVal;
11415
0
            for (int v : anValues)
11416
0
            {
11417
0
                if (!osVal.empty())
11418
0
                    osVal += ',';
11419
0
                osVal += std::to_string(v);
11420
0
            }
11421
0
            aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11422
0
                               osVal.c_str());
11423
0
        }
11424
0
    }
11425
11426
0
    auto hTransformer = GDALCreateGenImgProjTransformer2(
11427
0
        GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11428
0
        aosTO.List());
11429
0
    if (hTransformer == nullptr)
11430
0
    {
11431
0
        return CE_Failure;
11432
0
    }
11433
11434
0
    double z = 0;
11435
0
    int bSuccess = 0;
11436
0
    GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11437
0
                            &bSuccess);
11438
0
    GDALDestroyTransformer(hTransformer);
11439
0
    if (bSuccess)
11440
0
    {
11441
0
        if (pdfPixel)
11442
0
            *pdfPixel = dfGeolocX;
11443
0
        if (pdfLine)
11444
0
            *pdfLine = dfGeolocY;
11445
0
        return CE_None;
11446
0
    }
11447
0
    else
11448
0
    {
11449
0
        return CE_Failure;
11450
0
    }
11451
0
}
11452
11453
/************************************************************************/
11454
/*                 GDALDatasetGeolocationToPixelLine()                  */
11455
/************************************************************************/
11456
11457
/** Transform georeferenced coordinates to pixel/line coordinates.
11458
 *
11459
 * @see GDALDataset::GeolocationToPixelLine()
11460
 * @since GDAL 3.11
11461
 */
11462
11463
CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11464
                                         double dfGeolocY,
11465
                                         OGRSpatialReferenceH hSRS,
11466
                                         double *pdfPixel, double *pdfLine,
11467
                                         CSLConstList papszTransformerOptions)
11468
0
{
11469
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11470
11471
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11472
0
    return poDS->GeolocationToPixelLine(
11473
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11474
0
        pdfLine, papszTransformerOptions);
11475
0
}
11476
11477
/************************************************************************/
11478
/*                             GetExtent()                              */
11479
/************************************************************************/
11480
11481
/** Return extent of dataset in specified CRS.
11482
 *
11483
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11484
 *
11485
 * For rasters, the base implementation of this method only succeeds if
11486
 * GetGeoTransform() and GetSpatialRef() succeed.
11487
 * For vectors, the base implementation of this method iterates over layers
11488
 * and call their OGRLayer::GetExtent() method.
11489
 *
11490
 * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11491
 * time of this method is fast.
11492
 *
11493
 * This is the same as C function GDALGetExtent()
11494
 *
11495
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11496
 * @param poCRS CRS in which to express the extent. If not specified, this will
11497
 * be the raster CRS or the CRS of the first layer for a vector dataset.
11498
 * @return CE_None in case of success, CE_Failure otherwise
11499
 * @since GDAL 3.12
11500
 */
11501
11502
CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11503
                              const OGRSpatialReference *poCRS) const
11504
0
{
11505
0
    const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11506
0
    int nLayerCount = 0;
11507
0
    if (!poThisCRS)
11508
0
    {
11509
0
        nLayerCount = GetLayerCount();
11510
0
        if (nLayerCount >= 1)
11511
0
        {
11512
0
            if (auto poLayer = GetLayer(0))
11513
0
                poThisCRS = poLayer->GetSpatialRef();
11514
0
        }
11515
0
    }
11516
0
    if (!poCRS)
11517
0
        poCRS = poThisCRS;
11518
0
    else if (!poThisCRS)
11519
0
        return CE_Failure;
11520
11521
0
    *psExtent = OGREnvelope();
11522
11523
0
    GDALGeoTransform gt;
11524
0
    auto poThisDS = const_cast<GDALDataset *>(this);
11525
0
    const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11526
0
    if (bHasGT)
11527
0
    {
11528
0
        std::unique_ptr<OGRCoordinateTransformation> poCT;
11529
0
        if (poCRS)
11530
0
        {
11531
0
            poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11532
0
        }
11533
11534
0
        constexpr int DENSIFY_POINT_COUNT = 21;
11535
0
        double dfULX = gt.xorig;
11536
0
        double dfULY = gt.yorig;
11537
0
        double dfURX = 0, dfURY = 0;
11538
0
        gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11539
0
        double dfLLX = 0, dfLLY = 0;
11540
0
        gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11541
0
        double dfLRX = 0, dfLRY = 0;
11542
0
        gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11543
0
        const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11544
0
        const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11545
0
        const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11546
0
        const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11547
0
        if (poCT)
11548
0
        {
11549
0
            OGREnvelope sEnvTmp;
11550
0
            if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11551
0
                                       &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11552
0
                                       &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11553
0
            {
11554
0
                return CE_Failure;
11555
0
            }
11556
0
            *psExtent = sEnvTmp;
11557
0
        }
11558
0
        else
11559
0
        {
11560
0
            psExtent->MinX = xmin;
11561
0
            psExtent->MinY = ymin;
11562
0
            psExtent->MaxX = xmax;
11563
0
            psExtent->MaxY = ymax;
11564
0
        }
11565
0
    }
11566
11567
0
    if (nLayerCount > 0)
11568
0
    {
11569
0
        for (auto &&poLayer : poThisDS->GetLayers())
11570
0
        {
11571
0
            auto poLayerCRS = poLayer->GetSpatialRef();
11572
0
            if (poLayerCRS)
11573
0
            {
11574
0
                OGREnvelope sLayerExtent;
11575
0
                if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11576
0
                {
11577
0
                    auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11578
0
                        OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11579
0
                    if (poCT)
11580
0
                    {
11581
0
                        constexpr int DENSIFY_POINT_COUNT = 21;
11582
0
                        OGREnvelope sEnvTmp;
11583
0
                        if (poCT->TransformBounds(
11584
0
                                sLayerExtent.MinX, sLayerExtent.MinY,
11585
0
                                sLayerExtent.MaxX, sLayerExtent.MaxY,
11586
0
                                &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11587
0
                                &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11588
0
                                DENSIFY_POINT_COUNT))
11589
0
                        {
11590
0
                            psExtent->Merge(sEnvTmp);
11591
0
                        }
11592
0
                    }
11593
0
                }
11594
0
            }
11595
0
        }
11596
0
    }
11597
11598
0
    return psExtent->IsInit() ? CE_None : CE_Failure;
11599
0
}
11600
11601
/************************************************************************/
11602
/*                           GDALGetExtent()                            */
11603
/************************************************************************/
11604
11605
/** Return extent of dataset in specified CRS.
11606
 *
11607
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11608
 *
11609
 * For rasters, the base implementation of this method only succeeds if
11610
 * GetGeoTransform() and GetSpatialRef() succeed.
11611
 * For vectors, the base implementation of this method iterates over layers
11612
 * and call their OGRLayer::GetExtent() method.
11613
 *
11614
 * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11615
 * time of this method is fast.
11616
 *
11617
 * This is the same as C++ method GDALDataset::GetExtent()
11618
 *
11619
 * @param hDS Dataset handle. Must NOT be null.
11620
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11621
 * @param hCRS CRS in which to express the extent. If not specified, this will
11622
 * be the raster CRS or the CRS of the first layer for a vector dataset.
11623
 * @return extent in poCRS (valid only if IsInit() method returns true)
11624
 * @since GDAL 3.12
11625
 */
11626
11627
CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11628
                     OGRSpatialReferenceH hCRS)
11629
0
{
11630
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11631
0
    VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11632
0
    return GDALDataset::FromHandle(hDS)->GetExtent(
11633
0
        psExtent, OGRSpatialReference::FromHandle(hCRS));
11634
0
}
11635
11636
/************************************************************************/
11637
/*                       GetExtentWGS84LongLat()                        */
11638
/************************************************************************/
11639
11640
/** Return extent of dataset in WGS84 longitude/latitude
11641
 *
11642
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11643
 *
11644
 * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11645
 * time of this method is fast.
11646
 *
11647
 * This is the same as C function GDALGetExtentWGS84LongLat()
11648
 *
11649
 * @return extent (valid only if IsInit() method returns true)
11650
 * @since GDAL 3.12
11651
 */
11652
11653
CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11654
0
{
11655
0
    OGRSpatialReference oSRS_WGS84;
11656
0
    oSRS_WGS84.SetFromUserInput("WGS84");
11657
0
    oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11658
0
    return GetExtent(psExtent, &oSRS_WGS84);
11659
0
}
11660
11661
/************************************************************************/
11662
/*                     GDALGetExtentWGS84LongLat()                      */
11663
/************************************************************************/
11664
11665
/** Return extent of dataset in WGS84 longitude/latitude
11666
 *
11667
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11668
 *
11669
 * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11670
 * time of this method is fast.
11671
 *
11672
 * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11673
 *
11674
 * @param hDS Dataset handle. Must NOT be null.
11675
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11676
 * @return extent (valid only if IsInit() method returns true)
11677
 * @since GDAL 3.12
11678
 */
11679
11680
CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11681
0
{
11682
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11683
0
    VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11684
0
    return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11685
0
}
11686
11687
/************************************************************************/
11688
/*                  ReportUpdateNotSupportedByDriver()                  */
11689
/************************************************************************/
11690
11691
//! @cond Doxygen_Suppress
11692
11693
/* static */
11694
void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11695
0
{
11696
0
    CPLError(CE_Failure, CPLE_NotSupported,
11697
0
             "The %s driver does not support update access to existing "
11698
0
             "datasets.",
11699
0
             pszDriverName);
11700
0
}
11701
11702
//! @endcond
11703
11704
/************************************************************************/
11705
/*                           BuildFilename()                            */
11706
/************************************************************************/
11707
11708
/** Generates a filename, potentially relative to another one.
11709
 *
11710
 * Given the path to a reference directory, and a path to a file
11711
 * referenced from it, build a path to the file that the current application
11712
 * can use. If the file path is already absolute, rather than relative, or if
11713
 * bRelativeToReferencePath is false, then the filename of interest will be
11714
 * returned unaltered.
11715
 *
11716
 * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11717
 * into account the subdataset syntax.
11718
 *
11719
 * Examples:
11720
 * \code{.cpp}
11721
 * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11722
 * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11723
 * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11724
 * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11725
 * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11726
 * \endcode
11727
 *
11728
 * @param pszFilename Filename of interest.
11729
 * @param pszReferencePath Path to a reference directory.
11730
 * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11731
 *                                 relative to pszReferencePath
11732
 * @since 3.11
11733
 */
11734
11735
/* static */
11736
std::string GDALDataset::BuildFilename(const char *pszFilename,
11737
                                       const char *pszReferencePath,
11738
                                       bool bRelativeToReferencePath)
11739
0
{
11740
0
    std::string osSrcDSName;
11741
0
    if (pszReferencePath != nullptr && bRelativeToReferencePath)
11742
0
    {
11743
        // Try subdatasetinfo API first
11744
        // Note: this will become the only branch when subdatasetinfo will become
11745
        //       available for NITF_IM, RASTERLITE and TILEDB
11746
0
        const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11747
0
        if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11748
0
        {
11749
0
            auto path{oSubDSInfo->GetPathComponent()};
11750
0
            osSrcDSName = oSubDSInfo->ModifyPathComponent(
11751
0
                CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11752
0
                    .c_str());
11753
0
            GDALDestroySubdatasetInfo(oSubDSInfo);
11754
0
        }
11755
0
        else
11756
0
        {
11757
0
            bool bDone = false;
11758
0
            for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11759
0
            {
11760
0
                CPLString osPrefix(pszSyntax);
11761
0
                osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11762
0
                if (pszSyntax[osPrefix.size()] == '"')
11763
0
                    osPrefix += '"';
11764
0
                if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11765
0
                {
11766
0
                    if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11767
0
                    {
11768
0
                        const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11769
                        // CSV:z:/foo.xyz
11770
0
                        if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11771
0
                            pszLastPart - pszFilename >= 3 &&
11772
0
                            pszLastPart[-3] == ':')
11773
0
                        {
11774
0
                            pszLastPart -= 2;
11775
0
                        }
11776
0
                        CPLString osPrefixFilename = pszFilename;
11777
0
                        osPrefixFilename.resize(pszLastPart - pszFilename);
11778
0
                        osSrcDSName = osPrefixFilename +
11779
0
                                      CPLProjectRelativeFilenameSafe(
11780
0
                                          pszReferencePath, pszLastPart);
11781
0
                        bDone = true;
11782
0
                    }
11783
0
                    else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11784
0
                                            "{FILENAME}"))
11785
0
                    {
11786
0
                        CPLString osFilename(pszFilename + osPrefix.size());
11787
0
                        size_t nPos = 0;
11788
0
                        if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11789
0
                            (osFilename[2] == '\\' || osFilename[2] == '/'))
11790
0
                            nPos = 2;
11791
0
                        nPos = osFilename.find(
11792
0
                            pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11793
0
                            nPos);
11794
0
                        if (nPos != std::string::npos)
11795
0
                        {
11796
0
                            const CPLString osSuffix = osFilename.substr(nPos);
11797
0
                            osFilename.resize(nPos);
11798
0
                            osSrcDSName = osPrefix +
11799
0
                                          CPLProjectRelativeFilenameSafe(
11800
0
                                              pszReferencePath, osFilename) +
11801
0
                                          osSuffix;
11802
0
                            bDone = true;
11803
0
                        }
11804
0
                    }
11805
0
                    break;
11806
0
                }
11807
0
            }
11808
0
            if (!bDone)
11809
0
            {
11810
0
                std::string osReferencePath = pszReferencePath;
11811
0
                if (!CPLIsFilenameRelative(pszReferencePath))
11812
0
                {
11813
                    // Simplify path by replacing "foo/a/../b" with "foo/b"
11814
0
                    while (STARTS_WITH(pszFilename, "../"))
11815
0
                    {
11816
0
                        osReferencePath =
11817
0
                            CPLGetPathSafe(osReferencePath.c_str());
11818
0
                        pszFilename += strlen("../");
11819
0
                    }
11820
0
                }
11821
11822
0
                osSrcDSName = CPLProjectRelativeFilenameSafe(
11823
0
                    osReferencePath.c_str(), pszFilename);
11824
0
            }
11825
0
        }
11826
0
    }
11827
0
    else
11828
0
    {
11829
0
        osSrcDSName = pszFilename;
11830
0
    }
11831
0
    return osSrcDSName;
11832
0
}
11833
11834
/************************************************************************/
11835
/*                        GDALMDArrayFromDataset                        */
11836
/************************************************************************/
11837
11838
class GDALMDArrayFromDataset final : public GDALMDArray
11839
{
11840
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11841
11842
    GDALDataset *const m_poDS;
11843
    const GDALExtendedDataType m_dt;
11844
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11845
    std::string m_osUnit{};
11846
    std::vector<GByte> m_abyNoData{};
11847
    std::shared_ptr<GDALMDArray> m_varX{};
11848
    std::shared_ptr<GDALMDArray> m_varY{};
11849
    std::shared_ptr<GDALMDArray> m_varBand{};
11850
    const std::string m_osFilename;
11851
    const CPLStringList m_aosOptions;
11852
    int m_iBandDim = 0;
11853
    int m_iYDim = 1;
11854
    int m_iXDim = 2;
11855
    mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11856
11857
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11858
                   const size_t *count, const GInt64 *arrayStep,
11859
                   const GPtrDiff_t *bufferStride,
11860
                   const GDALExtendedDataType &bufferDataType,
11861
                   void *pBuffer) const;
11862
11863
  protected:
11864
    GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11865
0
        : GDALAbstractMDArray(std::string(),
11866
0
                              std::string(poDS->GetDescription())),
11867
0
          GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11868
0
          m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11869
0
                            poDS->GetRasterBand(1)->GetRasterDataType())),
11870
0
          m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11871
0
    {
11872
0
        m_poDS->Reference();
11873
11874
0
        const int nBandCount = poDS->GetRasterCount();
11875
0
        for (int i = 1; i <= nBandCount; ++i)
11876
0
        {
11877
0
            const auto poBand = poDS->GetRasterBand(i);
11878
0
            if (i == 1)
11879
0
                m_osUnit = poBand->GetUnitType();
11880
0
            else if (m_osUnit != poBand->GetUnitType())
11881
0
                m_osUnit.clear();
11882
11883
0
            std::vector<GByte> abyNoData;
11884
0
            int bHasNoData = false;
11885
0
            switch (poBand->GetRasterDataType())
11886
0
            {
11887
0
                case GDT_Int64:
11888
0
                {
11889
0
                    const auto nNoData =
11890
0
                        poBand->GetNoDataValueAsInt64(&bHasNoData);
11891
0
                    if (bHasNoData)
11892
0
                    {
11893
0
                        abyNoData.resize(m_dt.GetSize());
11894
0
                        GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11895
0
                                        m_dt.GetNumericDataType(), 0, 1);
11896
0
                    }
11897
0
                    break;
11898
0
                }
11899
11900
0
                case GDT_UInt64:
11901
0
                {
11902
0
                    const auto nNoData =
11903
0
                        poBand->GetNoDataValueAsUInt64(&bHasNoData);
11904
0
                    if (bHasNoData)
11905
0
                    {
11906
0
                        abyNoData.resize(m_dt.GetSize());
11907
0
                        GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11908
0
                                        m_dt.GetNumericDataType(), 0, 1);
11909
0
                    }
11910
0
                    break;
11911
0
                }
11912
11913
0
                default:
11914
0
                {
11915
0
                    const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11916
0
                    if (bHasNoData)
11917
0
                    {
11918
0
                        abyNoData.resize(m_dt.GetSize());
11919
0
                        GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11920
0
                                        &abyNoData[0],
11921
0
                                        m_dt.GetNumericDataType(), 0, 1);
11922
0
                    }
11923
0
                    break;
11924
0
                }
11925
0
            }
11926
11927
0
            if (i == 1)
11928
0
                m_abyNoData = std::move(abyNoData);
11929
0
            else if (m_abyNoData != abyNoData)
11930
0
                m_abyNoData.clear();
11931
0
        }
11932
11933
0
        const int nXSize = poDS->GetRasterXSize();
11934
0
        const int nYSize = poDS->GetRasterYSize();
11935
11936
0
        auto poSRS = poDS->GetSpatialRef();
11937
0
        std::string osTypeY;
11938
0
        std::string osTypeX;
11939
0
        std::string osDirectionY;
11940
0
        std::string osDirectionX;
11941
0
        if (poSRS && poSRS->GetAxesCount() == 2)
11942
0
        {
11943
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11944
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
11945
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
11946
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
11947
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
11948
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11949
0
            {
11950
0
                if (mapping == std::vector<int>{1, 2})
11951
0
                {
11952
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11953
0
                    osDirectionY = "NORTH";
11954
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11955
0
                    osDirectionX = "EAST";
11956
0
                }
11957
0
            }
11958
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11959
0
            {
11960
0
                if (mapping == std::vector<int>{2, 1})
11961
0
                {
11962
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11963
0
                    osDirectionY = "NORTH";
11964
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11965
0
                    osDirectionX = "EAST";
11966
0
                }
11967
0
            }
11968
0
        }
11969
11970
0
        const bool bBandYX = [papszOptions, poDS, nBandCount]()
11971
0
        {
11972
0
            const char *pszDimOrder =
11973
0
                CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11974
0
            if (EQUAL(pszDimOrder, "AUTO"))
11975
0
            {
11976
0
                const char *pszInterleave = poDS->GetMetadataItem(
11977
0
                    GDALMD_INTERLEAVE, GDAL_MDD_IMAGE_STRUCTURE);
11978
0
                return nBandCount == 1 || !pszInterleave ||
11979
0
                       !EQUAL(pszInterleave, "PIXEL");
11980
0
            }
11981
0
            else
11982
0
            {
11983
0
                return EQUAL(pszDimOrder, "BAND,Y,X");
11984
0
            }
11985
0
        }();
11986
0
        const char *const pszBandDimName =
11987
0
            CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11988
0
        auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11989
0
            "/", pszBandDimName, std::string(), std::string(), nBandCount);
11990
0
        const char *const pszYDimName =
11991
0
            CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11992
0
        auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11993
0
            "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11994
0
        const char *const pszXDimName =
11995
0
            CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11996
0
        auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11997
0
            "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11998
11999
0
        const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
12000
0
            papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
12001
0
        if (EQUAL(pszBandIndexingVarItem, "{Description}"))
12002
0
        {
12003
0
            const auto oIndexingVarType =
12004
0
                GDALExtendedDataType::CreateString(strlen("Band 65535"));
12005
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12006
0
                                                {poBandDim}, oIndexingVarType);
12007
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12008
0
            for (int i = 0; i < nBandCount; ++i)
12009
0
            {
12010
0
                const char *pszDesc =
12011
0
                    poDS->GetRasterBand(i + 1)->GetDescription();
12012
0
                const std::string osBandName =
12013
0
                    pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
12014
0
                const char *pszBandName = osBandName.c_str();
12015
0
                const char *const apszBandVal[] = {pszBandName};
12016
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12017
0
                const size_t anCount[] = {1};
12018
0
                const GInt64 arrayStep[] = {1};
12019
0
                const GPtrDiff_t anBufferStride[] = {1};
12020
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12021
0
                                 oIndexingVarType, apszBandVal);
12022
0
            }
12023
0
            m_varBand = std::move(poBandVar);
12024
0
            poBandDim->SetIndexingVariable(m_varBand);
12025
0
        }
12026
0
        else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
12027
0
        {
12028
0
            const auto oIndexingVarType =
12029
0
                GDALExtendedDataType::Create(GDT_Int32);
12030
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12031
0
                                                {poBandDim}, oIndexingVarType);
12032
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12033
0
            for (int i = 0; i < nBandCount; ++i)
12034
0
            {
12035
0
                const int anBandIdx[] = {i + 1};
12036
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12037
0
                const size_t anCount[] = {1};
12038
0
                const GInt64 arrayStep[] = {1};
12039
0
                const GPtrDiff_t anBufferStride[] = {1};
12040
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12041
0
                                 oIndexingVarType, anBandIdx);
12042
0
            }
12043
0
            m_varBand = std::move(poBandVar);
12044
0
            poBandDim->SetIndexingVariable(m_varBand);
12045
0
        }
12046
0
        else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
12047
0
        {
12048
0
            size_t nMaxLen = 0;
12049
0
            for (int i = 0; i < nBandCount; ++i)
12050
0
            {
12051
0
                const char *pszDesc = GDALGetColorInterpretationName(
12052
0
                    poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12053
0
                nMaxLen = std::max(nMaxLen, strlen(pszDesc));
12054
0
            }
12055
0
            const auto oIndexingVarType =
12056
0
                GDALExtendedDataType::CreateString(nMaxLen);
12057
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12058
0
                                                {poBandDim}, oIndexingVarType);
12059
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12060
0
            for (int i = 0; i < nBandCount; ++i)
12061
0
            {
12062
0
                const char *pszDesc = GDALGetColorInterpretationName(
12063
0
                    poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12064
0
                const char *const apszBandVal[] = {pszDesc};
12065
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12066
0
                const size_t anCount[] = {1};
12067
0
                const GInt64 arrayStep[] = {1};
12068
0
                const GPtrDiff_t anBufferStride[] = {1};
12069
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12070
0
                                 oIndexingVarType, apszBandVal);
12071
0
            }
12072
0
            m_varBand = std::move(poBandVar);
12073
0
            poBandDim->SetIndexingVariable(m_varBand);
12074
0
        }
12075
0
        else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
12076
0
        {
12077
0
            const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
12078
0
                papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
12079
0
            size_t nMaxLen = 0;
12080
0
            if (EQUAL(pszBandIndexingVarType, "String"))
12081
0
            {
12082
0
                for (int i = 0; i < nBandCount; ++i)
12083
0
                {
12084
0
                    const char *pszVal =
12085
0
                        poDS->GetRasterBand(i + 1)->GetMetadataItem(
12086
0
                            pszBandIndexingVarItem);
12087
0
                    if (pszVal)
12088
0
                        nMaxLen = std::max(nMaxLen, strlen(pszVal));
12089
0
                }
12090
0
            }
12091
0
            const auto oIndexingVarType =
12092
0
                EQUAL(pszBandIndexingVarType, "String")
12093
0
                    ? GDALExtendedDataType::CreateString(nMaxLen)
12094
0
                : EQUAL(pszBandIndexingVarType, "Integer")
12095
0
                    ? GDALExtendedDataType::Create(GDT_Int32)
12096
0
                    : GDALExtendedDataType::Create(GDT_Float64);
12097
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12098
0
                                                {poBandDim}, oIndexingVarType);
12099
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
12100
0
            for (int i = 0; i < nBandCount; ++i)
12101
0
            {
12102
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12103
0
                const size_t anCount[] = {1};
12104
0
                const GInt64 arrayStep[] = {1};
12105
0
                const GPtrDiff_t anBufferStride[] = {1};
12106
0
                const char *pszVal =
12107
0
                    poDS->GetRasterBand(i + 1)->GetMetadataItem(
12108
0
                        pszBandIndexingVarItem);
12109
0
                if (oIndexingVarType.GetClass() == GEDTC_STRING)
12110
0
                {
12111
0
                    const char *const apszBandVal[] = {pszVal ? pszVal : ""};
12112
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12113
0
                                     anBufferStride, oIndexingVarType,
12114
0
                                     apszBandVal);
12115
0
                }
12116
0
                else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12117
0
                {
12118
0
                    const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12119
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12120
0
                                     anBufferStride, oIndexingVarType, anVal);
12121
0
                }
12122
0
                else
12123
0
                {
12124
0
                    const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12125
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12126
0
                                     anBufferStride, oIndexingVarType, adfVal);
12127
0
                }
12128
0
            }
12129
0
            m_varBand = std::move(poBandVar);
12130
0
            poBandDim->SetIndexingVariable(m_varBand);
12131
0
        }
12132
12133
0
        GDALGeoTransform gt;
12134
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12135
0
        {
12136
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
12137
0
                "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12138
0
            poXDim->SetIndexingVariable(m_varX);
12139
12140
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
12141
0
                "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12142
0
            poYDim->SetIndexingVariable(m_varY);
12143
0
        }
12144
0
        if (bBandYX)
12145
0
        {
12146
0
            m_dims = {std::move(poBandDim), std::move(poYDim),
12147
0
                      std::move(poXDim)};
12148
0
        }
12149
0
        else
12150
0
        {
12151
0
            m_iYDim = 0;
12152
0
            m_iXDim = 1;
12153
0
            m_iBandDim = 2;
12154
0
            m_dims = {std::move(poYDim), std::move(poXDim),
12155
0
                      std::move(poBandDim)};
12156
0
        }
12157
0
    }
12158
12159
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12160
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12161
               const GDALExtendedDataType &bufferDataType,
12162
               void *pDstBuffer) const override;
12163
12164
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12165
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12166
                const GDALExtendedDataType &bufferDataType,
12167
                const void *pSrcBuffer) override
12168
0
    {
12169
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12170
0
                         bufferStride, bufferDataType,
12171
0
                         const_cast<void *>(pSrcBuffer));
12172
0
    }
12173
12174
  public:
12175
    ~GDALMDArrayFromDataset() override
12176
0
    {
12177
0
        m_poDS->ReleaseRef();
12178
0
    }
12179
12180
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12181
                                               CSLConstList papszOptions)
12182
0
    {
12183
0
        auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12184
0
            new GDALMDArrayFromDataset(poDS, papszOptions)));
12185
0
        array->SetSelf(array);
12186
0
        return array;
12187
0
    }
12188
12189
    bool IsWritable() const override
12190
0
    {
12191
0
        return m_poDS->GetAccess() == GA_Update;
12192
0
    }
12193
12194
    const std::string &GetFilename() const override
12195
0
    {
12196
0
        return m_osFilename;
12197
0
    }
12198
12199
    const std::vector<std::shared_ptr<GDALDimension>> &
12200
    GetDimensions() const override
12201
0
    {
12202
0
        return m_dims;
12203
0
    }
12204
12205
    const GDALExtendedDataType &GetDataType() const override
12206
0
    {
12207
0
        return m_dt;
12208
0
    }
12209
12210
    const std::string &GetUnit() const override
12211
0
    {
12212
0
        return m_osUnit;
12213
0
    }
12214
12215
    const void *GetRawNoDataValue() const override
12216
0
    {
12217
0
        return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12218
0
    }
12219
12220
    double GetOffset(bool *pbHasOffset,
12221
                     GDALDataType *peStorageType) const override
12222
0
    {
12223
0
        double dfRes = 0;
12224
0
        int bHasOffset = false;
12225
0
        auto poFirstBand = m_poDS->GetRasterBand(1);
12226
0
        if (poFirstBand)  // to avoid -Wnull-dereference
12227
0
        {
12228
0
            dfRes = poFirstBand->GetOffset(&bHasOffset);
12229
0
            for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12230
0
            {
12231
0
                const double dfOtherRes =
12232
0
                    m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12233
0
                bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12234
0
            }
12235
0
        }
12236
0
        if (pbHasOffset)
12237
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12238
0
        if (peStorageType)
12239
0
            *peStorageType = GDT_Unknown;
12240
0
        return dfRes;
12241
0
    }
12242
12243
    double GetScale(bool *pbHasScale,
12244
                    GDALDataType *peStorageType) const override
12245
0
    {
12246
0
        double dfRes = 0;
12247
0
        int bHasScale = false;
12248
0
        auto poFirstBand = m_poDS->GetRasterBand(1);
12249
0
        if (poFirstBand)  // to avoid -Wnull-dereference
12250
0
        {
12251
0
            dfRes = poFirstBand->GetScale(&bHasScale);
12252
0
            for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12253
0
            {
12254
0
                const double dfOtherRes =
12255
0
                    m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12256
0
                bHasScale = bHasScale && (dfOtherRes == dfRes);
12257
0
            }
12258
0
        }
12259
0
        if (pbHasScale)
12260
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
12261
0
        if (peStorageType)
12262
0
            *peStorageType = GDT_Unknown;
12263
0
        return dfRes;
12264
0
    }
12265
12266
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12267
0
    {
12268
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
12269
0
        if (!poSrcSRS)
12270
0
            return nullptr;
12271
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12272
12273
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12274
0
        for (auto &m : axisMapping)
12275
0
        {
12276
0
            if (m == 1)
12277
0
                m = m_iXDim + 1;
12278
0
            else if (m == 2)
12279
0
                m = m_iYDim + 1;
12280
0
            else
12281
0
                m = 0;
12282
0
        }
12283
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12284
0
        return poSRS;
12285
0
    }
12286
12287
    std::vector<GUInt64> GetBlockSize() const override
12288
0
    {
12289
0
        int nBlockXSize = 0;
12290
0
        int nBlockYSize = 0;
12291
0
        m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12292
0
        if (m_iBandDim == 0)
12293
0
        {
12294
0
            return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12295
0
                                        static_cast<GUInt64>(nBlockXSize)};
12296
0
        }
12297
0
        else
12298
0
        {
12299
0
            return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12300
0
                                        static_cast<GUInt64>(nBlockXSize), 1};
12301
0
        }
12302
0
    }
12303
12304
    std::vector<std::shared_ptr<GDALAttribute>>
12305
    GetAttributes(CSLConstList) const override
12306
0
    {
12307
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
12308
0
        auto papszMD = m_poDS->GetMetadata();
12309
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
12310
0
        {
12311
0
            char *pszKey = nullptr;
12312
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12313
0
            if (pszKey && pszValue)
12314
0
            {
12315
0
                res.emplace_back(
12316
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12317
0
            }
12318
0
            CPLFree(pszKey);
12319
0
        }
12320
0
        return res;
12321
0
    }
12322
12323
    int GetOverviewCount() const override
12324
0
    {
12325
0
        int nOvrCount = 0;
12326
0
        GDALDataset *poOvrDS = nullptr;
12327
0
        bool bOK = true;
12328
0
        for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12329
0
        {
12330
0
            auto poBand = m_poDS->GetRasterBand(i);
12331
0
            const int nThisOvrCount = poBand->GetOverviewCount();
12332
0
            bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12333
0
            if (bOK)
12334
0
            {
12335
0
                nOvrCount = nThisOvrCount;
12336
0
                auto poFirstOvrBand = poBand->GetOverview(0);
12337
0
                bOK = poFirstOvrBand != nullptr;
12338
0
                if (bOK)
12339
0
                {
12340
0
                    auto poThisOvrDS = poFirstOvrBand->GetDataset();
12341
0
                    bOK = poThisOvrDS != nullptr &&
12342
0
                          poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12343
0
                          (i == 1 || poThisOvrDS == poOvrDS);
12344
0
                    if (bOK)
12345
0
                        poOvrDS = poThisOvrDS;
12346
0
                }
12347
0
            }
12348
0
        }
12349
0
        return bOK ? nOvrCount : 0;
12350
0
    }
12351
12352
    std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12353
0
    {
12354
0
        const int nOverviews = GetOverviewCount();
12355
0
        if (idx < 0 || idx >= nOverviews)
12356
0
            return nullptr;
12357
0
        m_apoOverviews.resize(nOverviews);
12358
0
        if (!m_apoOverviews[idx])
12359
0
        {
12360
0
            if (auto poBand = m_poDS->GetRasterBand(1))
12361
0
            {
12362
0
                if (auto poOvrBand = poBand->GetOverview(idx))
12363
0
                {
12364
0
                    if (auto poOvrDS = poOvrBand->GetDataset())
12365
0
                    {
12366
0
                        m_apoOverviews[idx] =
12367
0
                            Create(poOvrDS, m_aosOptions.List());
12368
0
                    }
12369
0
                }
12370
0
            }
12371
0
        }
12372
0
        return m_apoOverviews[idx];
12373
0
    }
12374
};
12375
12376
bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12377
                                   const size_t *count, const GInt64 *arrayStep,
12378
                                   const GPtrDiff_t *bufferStride,
12379
                                   const GDALExtendedDataType &bufferDataType,
12380
                                   void *pDstBuffer) const
12381
0
{
12382
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12383
0
                     bufferDataType, pDstBuffer);
12384
0
}
12385
12386
/************************************************************************/
12387
/*                             ReadWrite()                              */
12388
/************************************************************************/
12389
12390
bool GDALMDArrayFromDataset::ReadWrite(
12391
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12392
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12393
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12394
0
{
12395
0
    const auto eDT(bufferDataType.GetNumericDataType());
12396
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12397
0
    const int nX =
12398
0
        arrayStep[m_iXDim] > 0
12399
0
            ? static_cast<int>(arrayStartIdx[m_iXDim])
12400
0
            : static_cast<int>(arrayStartIdx[m_iXDim] -
12401
0
                               (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12402
0
    const int nY =
12403
0
        arrayStep[m_iYDim] > 0
12404
0
            ? static_cast<int>(arrayStartIdx[m_iYDim])
12405
0
            : static_cast<int>(arrayStartIdx[m_iYDim] -
12406
0
                               (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12407
0
    const int nSizeX =
12408
0
        static_cast<int>(count[m_iXDim] * std::abs(arrayStep[m_iXDim]));
12409
0
    const int nSizeY =
12410
0
        static_cast<int>(count[m_iYDim] * std::abs(arrayStep[m_iYDim]));
12411
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12412
0
    int nStrideXSign = 1;
12413
0
    if (arrayStep[m_iXDim] < 0)
12414
0
    {
12415
0
        pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12416
0
        nStrideXSign = -1;
12417
0
    }
12418
0
    int nStrideYSign = 1;
12419
0
    if (arrayStep[m_iYDim] < 0)
12420
0
    {
12421
0
        pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12422
0
        nStrideYSign = -1;
12423
0
    }
12424
0
    const GSpacing nPixelSpace =
12425
0
        static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12426
0
    const GSpacing nLineSpace =
12427
0
        static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12428
0
    const GSpacing nBandSpace =
12429
0
        static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12430
0
    std::vector<int> anBandList;
12431
0
    for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12432
0
        anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12433
0
                             i * static_cast<int>(arrayStep[m_iBandDim]));
12434
12435
0
    return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12436
0
                            static_cast<int>(count[m_iXDim]),
12437
0
                            static_cast<int>(count[m_iYDim]), eDT,
12438
0
                            static_cast<int>(count[m_iBandDim]),
12439
0
                            anBandList.data(), nPixelSpace, nLineSpace,
12440
0
                            nBandSpace, nullptr) == CE_None;
12441
0
}
12442
12443
/************************************************************************/
12444
/*                             AsMDArray()                              */
12445
/************************************************************************/
12446
12447
/** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12448
 *
12449
 * If this dataset is not already marked as shared, it will be, so that the
12450
 * returned array holds a reference to it.
12451
 *
12452
 * If the dataset has a geotransform attached, the X and Y dimensions of the
12453
 * returned array will have an associated indexing variable.
12454
 *
12455
 * The currently supported list of options is:
12456
 * <ul>
12457
 * <li>DIM_ORDER=&lt;order&gt; where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12458
 * "Band,Y,X" means that the first (slowest changing) dimension is Band
12459
 * and the last (fastest changing direction) is X
12460
 * "Y,X,Band" means that the first (slowest changing) dimension is Y
12461
 * and the last (fastest changing direction) is Band.
12462
 * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12463
 * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12464
 * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12465
 * "Y,X,Band" is use.
12466
 * </li>
12467
 * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|&lt;BandMetadataItem&gt;:
12468
 * item from which to build the band indexing variable.
12469
 * <ul>
12470
 * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12471
 * <li>"{None}" means that no band indexing variable must be created.</li>
12472
 * <li>"{Index}" means that the band index (starting at one) is used.</li>
12473
 * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12474
 * <li>&lt;BandMetadataItem&gt; is the name of a band metadata item to use.</li>
12475
 * </ul>
12476
 * </li>
12477
 * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12478
 * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12479
 * Defaults to String.
12480
 * </li>
12481
 * <li>BAND_DIM_NAME=&lt;string&gt;: Name of the band dimension.
12482
 * Defaults to "Band".
12483
 * </li>
12484
 * <li>X_DIM_NAME=&lt;string&gt;: Name of the X dimension. Defaults to "X".
12485
 * </li>
12486
 * <li>Y_DIM_NAME=&lt;string&gt;: Name of the Y dimension. Defaults to "Y".
12487
 * </li>
12488
 * </ul>
12489
 *
12490
 * This is the same as the C function GDALDatasetAsMDArray().
12491
 *
12492
 * The "reverse" method is GDALMDArray::AsClassicDataset().
12493
 *
12494
 * @param papszOptions Null-terminated list of strings, or nullptr.
12495
 * @return a new array, or nullptr.
12496
 *
12497
 * @since GDAL 3.12
12498
 */
12499
std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12500
0
{
12501
0
    if (!GetShared())
12502
0
    {
12503
0
        MarkAsShared();
12504
0
    }
12505
0
    if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12506
0
    {
12507
0
        ReportError(
12508
0
            CE_Failure, CPLE_AppDefined,
12509
0
            "Degenerated array (band, Y and/or X dimension of size zero)");
12510
0
        return nullptr;
12511
0
    }
12512
0
    const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12513
0
    for (int i = 1; i < nBands; ++i)
12514
0
    {
12515
0
        if (eDT != papoBands[i]->GetRasterDataType())
12516
0
        {
12517
0
            ReportError(CE_Failure, CPLE_AppDefined,
12518
0
                        "Non-uniform data type amongst bands");
12519
0
            return nullptr;
12520
0
        }
12521
0
    }
12522
0
    const char *pszDimOrder =
12523
0
        CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12524
0
    if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12525
0
        !EQUAL(pszDimOrder, "Y,X,Band"))
12526
0
    {
12527
0
        ReportError(CE_Failure, CPLE_IllegalArg,
12528
0
                    "Illegal value for DIM_ORDER option");
12529
0
        return nullptr;
12530
0
    }
12531
0
    return GDALMDArrayFromDataset::Create(this, papszOptions);
12532
0
}
12533
12534
/************************************************************************/
12535
/*             GDALDataset::GetInterBandCovarianceMatrix()              */
12536
/************************************************************************/
12537
12538
/**
12539
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12540
12541
 The covariance indicates the level to which two bands vary together.
12542
12543
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12544
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12545
12546
 \f[
12547
    \mathrm{cov}[i,j] =
12548
    \frac{
12549
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12550
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12551
    }{
12552
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12553
    }
12554
 \f]
12555
12556
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12557
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12558
 is symmetric.
12559
12560
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12561
 if the pixels in bands are considered to be a sample of the whole population.
12562
 This is consistent with the default of
12563
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12564
 matrix is consistent with what can be obtained with
12565
12566
 \verbatim embed:rst
12567
 .. code-block:: python
12568
12569
     numpy.cov(
12570
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12571
     )
12572
 \endverbatim
12573
12574
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12575
 to be the whole population.
12576
12577
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12578
 this method uses them.
12579
 Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12580
 Otherwise, if bForce is false, an empty vector is returned
12581
12582
 @param nBandCount Zero for all bands, or number of values in panBandList.
12583
                   Defaults to 0.
12584
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12585
                    nBandCount values such as panBandList[i] is the index
12586
                    between 1 and GetRasterCount() of a band that must be used
12587
                    in the covariance computation. Defaults to nullptr.
12588
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12589
                  ComputeInterBandCovarianceMatrix().
12590
                  Defaults to false.
12591
 @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12592
               when the STATISTICS_COVARIANCES metadata items are missing.
12593
               Defaults to false.
12594
 @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12595
                           write STATISTICS_COVARIANCES band metadata items.
12596
                           Defaults to true.
12597
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12598
                              averaging phase of the covariance computation.
12599
                              Defaults to 1.
12600
 @param pfnProgress a function to call to report progress, or NULL.
12601
 @param pProgressData application data to pass to the progress function.
12602
12603
 @return a vector of nBandCount * nBandCount values if successful,
12604
         in row-major order, or an empty vector in case of failure
12605
12606
 @since 3.13
12607
12608
 @see ComputeInterBandCovarianceMatrix()
12609
 */
12610
12611
std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12612
    int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12613
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12614
    GDALProgressFunc pfnProgress, void *pProgressData)
12615
0
{
12616
0
    std::vector<double> res;
12617
0
    const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12618
0
    if (nBandCountToUse == 0)
12619
0
        return res;
12620
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
12621
    {
12622
        // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12623
        if (static_cast<uint32_t>(nBandCountToUse) >
12624
            std::numeric_limits<uint16_t>::max())
12625
        {
12626
            CPLError(CE_Failure, CPLE_OutOfMemory,
12627
                     "Not enough memory to store result");
12628
            return res;
12629
        }
12630
    }
12631
0
    try
12632
0
    {
12633
0
        res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12634
0
    }
12635
0
    catch (const std::exception &)
12636
0
    {
12637
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
12638
0
                 "Not enough memory to store result");
12639
0
        return res;
12640
0
    }
12641
12642
0
    if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12643
0
                                     panBandList, bApproxOK, bForce,
12644
0
                                     bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12645
0
                                     pfnProgress, pProgressData) != CE_None)
12646
0
    {
12647
0
        res.clear();
12648
0
    }
12649
0
    return res;
12650
0
}
12651
12652
/************************************************************************/
12653
/*             GDALDataset::GetInterBandCovarianceMatrix()              */
12654
/************************************************************************/
12655
12656
/**
12657
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12658
12659
 The covariance indicates the level to which two bands vary together.
12660
12661
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12662
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12663
12664
 \f[
12665
    \mathrm{cov}[i,j] =
12666
    \frac{
12667
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12668
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12669
    }{
12670
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12671
    }
12672
 \f]
12673
12674
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12675
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12676
 is symmetric.
12677
12678
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12679
 if the pixels in bands are considered to be a sample of the whole population.
12680
 This is consistent with the default of
12681
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12682
 matrix is consistent with what can be obtained with
12683
12684
 \verbatim embed:rst
12685
 .. code-block:: python
12686
12687
     numpy.cov(
12688
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12689
     )
12690
 \endverbatim
12691
12692
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12693
 to be the whole population.
12694
12695
 The caller must provide an already allocated array in padfCovMatrix of size
12696
 at least nBandCount * nBandCount.
12697
12698
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12699
 this method uses them.
12700
 Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12701
 Otherwise, if bForce is false, an empty vector is returned
12702
12703
 This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12704
12705
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12706
                      nBandCount * nBandCount.
12707
 @param nSize Number of elements in output array.
12708
 @param nBandCount Zero for all bands, or number of values in panBandList.
12709
                   Defaults to 0.
12710
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12711
                    nBandCount values such as panBandList[i] is the index
12712
                    between 1 and GetRasterCount() of a band that must be used
12713
                    in the covariance computation. Defaults to nullptr.
12714
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12715
                  ComputeInterBandCovarianceMatrix().
12716
                  Defaults to false.
12717
 @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12718
               when the STATISTICS_COVARIANCES metadata items are missing.
12719
               Defaults to false.
12720
 @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12721
                           write STATISTICS_COVARIANCES band metadata items.
12722
                           Defaults to true.
12723
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12724
                              averaging phase of the covariance computation.
12725
                              Defaults to 1.
12726
 @param pfnProgress a function to call to report progress, or NULL.
12727
 @param pProgressData application data to pass to the progress function.
12728
12729
 @return CE_None if successful, CE_Warning if values are not available in
12730
         metadata and bForce is false, or CE_Failure in case of failure
12731
12732
 @since 3.13
12733
12734
 @see ComputeInterBandCovarianceMatrix()
12735
 */
12736
12737
CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12738
    double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12739
    bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12740
    int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12741
    void *pProgressData)
12742
0
{
12743
0
    std::vector<int> anBandListTmp;  // keep in this scope
12744
0
    if (nBandCount == 0)
12745
0
    {
12746
0
        if (nBands == 0)
12747
0
            return CE_None;
12748
0
        for (int i = 0; i < nBands; ++i)
12749
0
            anBandListTmp.push_back(i + 1);
12750
0
        nBandCount = nBands;
12751
0
        panBandList = anBandListTmp.data();
12752
0
    }
12753
0
    else
12754
0
    {
12755
0
        if (nBandCount > nBands)
12756
0
        {
12757
0
            CPLError(CE_Failure, CPLE_AppDefined,
12758
0
                     "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12759
0
            return CE_Failure;
12760
0
        }
12761
0
        for (int i = 0; i < nBandCount; ++i)
12762
0
        {
12763
0
            if (panBandList[i] <= 0 || panBandList[i] > nBands)
12764
0
            {
12765
0
                CPLError(CE_Failure, CPLE_AppDefined,
12766
0
                         "GetInterBandCovarianceMatrix(): invalid value "
12767
0
                         "panBandList[%d] = %d",
12768
0
                         i, panBandList[i]);
12769
0
                return CE_Failure;
12770
0
            }
12771
0
        }
12772
0
    }
12773
12774
0
    if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12775
0
    {
12776
0
        CPLError(
12777
0
            CE_Failure, CPLE_AppDefined,
12778
0
            "GetInterBandCovarianceMatrix(): too small result matrix provided");
12779
0
        return CE_Failure;
12780
0
    }
12781
0
    bool bGotFromMD = true;
12782
0
    size_t resIdx = 0;
12783
0
    for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12784
0
    {
12785
0
        const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12786
0
            "STATISTICS_COVARIANCES");
12787
0
        bGotFromMD = pszCov != nullptr;
12788
0
        if (bGotFromMD)
12789
0
        {
12790
0
            const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12791
0
            bGotFromMD = aosTokens.size() == nBands;
12792
0
            if (bGotFromMD)
12793
0
            {
12794
0
                for (int j = 0; j < nBandCount; ++j)
12795
0
                    padfCovMatrix[resIdx++] =
12796
0
                        CPLAtof(aosTokens[panBandList[j] - 1]);
12797
0
            }
12798
0
        }
12799
0
    }
12800
0
    if (bGotFromMD)
12801
0
        return CE_None;
12802
12803
0
    if (!bForce)
12804
0
        return CE_Warning;
12805
0
    return ComputeInterBandCovarianceMatrix(
12806
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12807
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12808
0
}
12809
12810
/************************************************************************/
12811
/*              GDALDatasetGetInterBandCovarianceMatrix()               */
12812
/************************************************************************/
12813
12814
/**
12815
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12816
12817
 The covariance indicates the level to which two bands vary together.
12818
12819
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12820
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12821
12822
 \f[
12823
    \mathrm{cov}[i,j] =
12824
    \frac{
12825
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12826
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12827
    }{
12828
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12829
    }
12830
 \f]
12831
12832
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12833
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12834
 is symmetric.
12835
12836
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12837
 if the pixels in bands are considered to be a sample of the whole population.
12838
 This is consistent with the default of
12839
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12840
 matrix is consistent with what can be obtained with
12841
12842
 \verbatim embed:rst
12843
 .. code-block:: python
12844
12845
     numpy.cov(
12846
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12847
     )
12848
 \endverbatim
12849
12850
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12851
 to be the whole population.
12852
12853
 The caller must provide an already allocated array in padfCovMatrix of size
12854
 at least nBandCount * nBandCount.
12855
12856
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12857
 this method uses them.
12858
 Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12859
 Otherwise, if bForce is false, an empty vector is returned
12860
12861
 This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12862
12863
 @param hDS Dataset handle.
12864
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12865
                      nBandCount * nBandCount.
12866
 @param nSize Number of elements in output array.
12867
 @param nBandCount Zero for all bands, or number of values in panBandList.
12868
                   Defaults to 0.
12869
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12870
                    nBandCount values such as panBandList[i] is the index
12871
                    between 1 and GetRasterCount() of a band that must be used
12872
                    in the covariance computation. Defaults to nullptr.
12873
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12874
                  GDALDatasetComputeInterBandCovarianceMatrix().
12875
                  Defaults to false.
12876
 @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12877
               when the STATISTICS_COVARIANCES metadata items are missing.
12878
               Defaults to false.
12879
 @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12880
                           write STATISTICS_COVARIANCES band metadata items.
12881
                           Defaults to true.
12882
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12883
                              averaging phase of the covariance computation.
12884
                              Defaults to 1.
12885
 @param pfnProgress a function to call to report progress, or NULL.
12886
 @param pProgressData application data to pass to the progress function.
12887
12888
 @return CE_None if successful, CE_Warning if values are not available in
12889
         metadata and bForce is false, or CE_Failure in case of failure
12890
12891
 @since 3.13
12892
12893
 @see GDALDatasetComputeInterBandCovarianceMatrix()
12894
 */
12895
CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12896
    GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12897
    const int *panBandList, bool bApproxOK, bool bForce,
12898
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12899
    GDALProgressFunc pfnProgress, void *pProgressData)
12900
0
{
12901
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12902
0
    VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12903
0
    return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12904
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12905
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12906
0
}
12907
12908
/************************************************************************/
12909
/*           GDALDataset::ComputeInterBandCovarianceMatrix()            */
12910
/************************************************************************/
12911
12912
/**
12913
 \brief Compute the covariance matrix between bands of this dataset.
12914
12915
 The covariance indicates the level to which two bands vary together.
12916
12917
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12918
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12919
12920
 \f[
12921
    \mathrm{cov}[i,j] =
12922
    \frac{
12923
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12924
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12925
    }{
12926
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12927
    }
12928
 \f]
12929
12930
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12931
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12932
 is symmetric.
12933
12934
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12935
 if the pixels in bands are considered to be a sample of the whole population.
12936
 This is consistent with the default of
12937
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12938
 matrix is consistent with what can be obtained with
12939
12940
 \verbatim embed:rst
12941
 .. code-block:: python
12942
12943
     numpy.cov(
12944
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12945
     )
12946
 \endverbatim
12947
12948
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12949
 to be the whole population.
12950
12951
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12952
 metadata items are available in bands. See GetInterBandCovarianceMatrix()
12953
 to use them.
12954
12955
 @param nBandCount Zero for all bands, or number of values in panBandList.
12956
                   Defaults to 0.
12957
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12958
                    nBandCount values such as panBandList[i] is the index
12959
                    between 1 and GetRasterCount() of a band that must be used
12960
                    in the covariance computation. Defaults to nullptr.
12961
 @param bApproxOK Whether it is acceptable to use a subsample of values.
12962
                  Defaults to false.
12963
 @param bWriteIntoMetadata Whether this method must write
12964
                           STATISTICS_COVARIANCES band metadata items.
12965
                           Defaults to true.
12966
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12967
                              averaging phase of the covariance computation.
12968
                              Defaults to 1.
12969
 @param pfnProgress a function to call to report progress, or NULL.
12970
 @param pProgressData application data to pass to the progress function.
12971
12972
 @return a vector of nBandCount * nBandCount values if successful,
12973
         in row-major order, or an empty vector in case of failure
12974
12975
 @since 3.13
12976
12977
 @see GetInterBandCovarianceMatrix()
12978
 */
12979
std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12980
    int nBandCount, const int *panBandList, bool bApproxOK,
12981
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12982
    GDALProgressFunc pfnProgress, void *pProgressData)
12983
0
{
12984
0
    std::vector<double> res;
12985
0
    const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12986
0
    if (nBandCountToUse == 0)
12987
0
        return res;
12988
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
12989
    {
12990
        // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12991
        if (static_cast<uint32_t>(nBandCountToUse) >
12992
            std::numeric_limits<uint16_t>::max())
12993
        {
12994
            CPLError(CE_Failure, CPLE_OutOfMemory,
12995
                     "Not enough memory to store result");
12996
            return res;
12997
        }
12998
    }
12999
0
    try
13000
0
    {
13001
0
        res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
13002
0
    }
13003
0
    catch (const std::exception &)
13004
0
    {
13005
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
13006
0
                 "Not enough memory to store result");
13007
0
        return res;
13008
0
    }
13009
13010
0
    if (ComputeInterBandCovarianceMatrix(
13011
0
            res.data(), res.size(), nBandCount, panBandList, bApproxOK,
13012
0
            bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
13013
0
            pProgressData) != CE_None)
13014
0
        res.clear();
13015
0
    return res;
13016
0
}
13017
13018
/************************************************************************/
13019
/*              ComputeInterBandCovarianceMatrixInternal()              */
13020
/************************************************************************/
13021
13022
template <class T>
13023
// CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
13024
// causes that to happen
13025
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
13026
ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
13027
                                         double *padfCovMatrix, int nBandCount,
13028
                                         const int *panBandList,
13029
                                         GDALRasterBand *const *papoBands,
13030
                                         int nDeltaDegreeOfFreedom,
13031
                                         GDALProgressFunc pfnProgress,
13032
                                         void *pProgressData)
13033
0
{
13034
    // We use the padfCovMatrix to accumulate co-moments
13035
    // Dimension = nBandCount * nBandCount
13036
0
    double *const padfComomentMatrix = padfCovMatrix;
13037
13038
    // Matrix of  nBandCount * nBandCount storing co-moments, in optimized
13039
    // case when the block has no nodata value
13040
    // Only used if T != double
13041
0
    [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
13042
13043
    // Count number of valid values in padfComomentMatrix for each (i,j) tuple
13044
    // Updated while iterating over blocks
13045
    // Dimension = nBandCount * nBandCount
13046
0
    std::vector<uint64_t> anCount;
13047
13048
    // Mean of bands, for each (i,j) tuple.
13049
    // Updated while iterating over blocks.
13050
    // This is a matrix rather than a vector due to the fact when need to update
13051
    // it in sync with padfComomentMatrix
13052
    // Dimension = nBandCount * nBandCount
13053
0
    std::vector<T> adfMean;
13054
13055
    // Number of valid values when computing adfMean, for each (i,j) tuple.
13056
    // Updated while iterating over blocks.
13057
    // This is a matrix rather than a vector due to the fact when need to update
13058
    // it in sync with padfComomentMatrix
13059
    // Dimension = nBandCount * nBandCount
13060
0
    std::vector<uint64_t> anCountMean;
13061
13062
    // Mean of values for each band i. Refreshed for each block.
13063
    // Dimension = nBandCount
13064
0
    std::vector<T> adfCurBlockMean;
13065
13066
    // Number of values participating to the mean for each band i.
13067
    // Refreshed for each block. Dimension = nBandCount
13068
0
    std::vector<size_t> anCurBlockCount;
13069
13070
    // Pixel values for all selected values for the current block
13071
    // Dimension = nBlockXSize * nBlockYSize * nBandCount
13072
0
    std::vector<T> adfCurBlockPixelsAllBands;
13073
13074
    // Vector of nodata values for all bands. Dimension = nBandCount
13075
0
    std::vector<T> adfNoData;
13076
13077
    // Vector of mask bands for all bands. Dimension = nBandCount
13078
0
    std::vector<GDALRasterBand *> apoMaskBands;
13079
13080
    // Vector of vector of mask values. Dimension = nBandCount
13081
0
    std::vector<std::vector<GByte>> aabyCurBlockMask;
13082
13083
    // Vector of pointer to vector of mask values. Dimension = nBandCount
13084
0
    std::vector<std::vector<GByte> *> pabyCurBlockMask;
13085
13086
0
    int nBlockXSize = 0;
13087
0
    int nBlockYSize = 0;
13088
0
    papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
13089
13090
0
    if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
13091
0
        std::numeric_limits<size_t>::max() / nBandCount)
13092
0
    {
13093
0
        poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13094
0
                          "Not enough memory for intermediate computations");
13095
0
        return CE_Failure;
13096
0
    }
13097
0
    const size_t nPixelsInBlock =
13098
0
        static_cast<size_t>(nBlockXSize) * nBlockYSize;
13099
13100
    // Allocate temporary matrices and vectors
13101
0
    const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13102
13103
0
    using MySignedSize_t = std::make_signed_t<size_t>;
13104
0
    const auto kMax =
13105
0
        static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
13106
0
    std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
13107
0
    try
13108
0
    {
13109
0
        anCount.resize(nMatrixSize);
13110
0
        adfMean.resize(nMatrixSize);
13111
0
        anCountMean.resize(nMatrixSize);
13112
13113
        if constexpr (!std::is_same_v<T, double>)
13114
        {
13115
            aCurBlockComomentMatrix.resize(nMatrixSize);
13116
        }
13117
13118
0
        anMapLinearIdxToIJ.resize(kMax);
13119
13120
0
        adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13121
13122
0
        adfCurBlockMean.resize(nBandCount);
13123
0
        anCurBlockCount.resize(nBandCount);
13124
0
        adfNoData.resize(nBandCount);
13125
0
        apoMaskBands.resize(nBandCount);
13126
0
        aabyCurBlockMask.resize(nBandCount);
13127
0
        pabyCurBlockMask.resize(nBandCount);
13128
0
    }
13129
0
    catch (const std::exception &)
13130
0
    {
13131
0
        poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13132
0
                          "Not enough memory for intermediate computations");
13133
0
        return CE_Failure;
13134
0
    }
13135
13136
0
    constexpr T ZERO{0};
13137
0
    std::fill(padfComomentMatrix,
13138
0
              padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13139
0
              0);
13140
13141
0
    {
13142
0
        MySignedSize_t nLinearIdx = 0;
13143
0
        for (int i = 0; i < nBandCount; ++i)
13144
0
        {
13145
0
            for (int j = i; j < nBandCount; ++j)
13146
0
            {
13147
0
                anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13148
0
                ++nLinearIdx;
13149
0
            }
13150
0
        }
13151
0
    }
13152
13153
    // Fetch nodata values and mask bands
13154
0
    bool bAllBandsSameMask = false;
13155
0
    bool bIsAllInteger = false;
13156
0
    bool bNoneHasMaskOrNodata = false;
13157
0
    for (int i = 0; i < nBandCount; ++i)
13158
0
    {
13159
0
        const auto poBand = papoBands[panBandList[i] - 1];
13160
0
        bIsAllInteger = (i == 0 || bIsAllInteger) &&
13161
0
                        GDALDataTypeIsInteger(poBand->GetRasterDataType());
13162
0
        int bHasNoData = FALSE;
13163
0
        double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13164
0
        if (!bHasNoData)
13165
0
        {
13166
0
            dfNoData = std::numeric_limits<double>::quiet_NaN();
13167
13168
0
            if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13169
0
                poBand->GetColorInterpretation() != GCI_AlphaBand)
13170
0
            {
13171
0
                apoMaskBands[i] = poBand->GetMaskBand();
13172
0
                try
13173
0
                {
13174
0
                    aabyCurBlockMask[i].resize(nPixelsInBlock);
13175
0
                }
13176
0
                catch (const std::exception &)
13177
0
                {
13178
0
                    poDS->ReportError(
13179
0
                        CE_Failure, CPLE_OutOfMemory,
13180
0
                        "Not enough memory for intermediate computations");
13181
0
                    return CE_Failure;
13182
0
                }
13183
0
#ifndef __COVERITY__
13184
                // coverity[escape]
13185
0
                pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13186
0
#endif
13187
0
            }
13188
0
        }
13189
0
        adfNoData[i] = static_cast<T>(dfNoData);
13190
0
        if (i == 0)
13191
0
            bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13192
0
        else if (bAllBandsSameMask)
13193
0
            bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13194
13195
0
        bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13196
0
                               std::isnan(dfNoData) &&
13197
0
                               apoMaskBands[i] == nullptr;
13198
0
    }
13199
0
    if (bAllBandsSameMask)
13200
0
    {
13201
0
        for (int i = 1; i < nBandCount; ++i)
13202
0
        {
13203
0
            apoMaskBands[i] = nullptr;
13204
0
            aabyCurBlockMask[i].clear();
13205
0
            pabyCurBlockMask[i] = pabyCurBlockMask[0];
13206
0
        }
13207
0
    }
13208
13209
0
    const auto nIterCount =
13210
0
        static_cast<uint64_t>(
13211
0
            cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13212
0
        cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13213
0
    uint64_t nCurIter = 0;
13214
13215
0
    int nNumThreads = 1;
13216
#ifdef HAVE_OPENMP
13217
    if (nBandCount >= 100)
13218
    {
13219
        const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13220
        nNumThreads =
13221
            GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13222
    }
13223
#endif
13224
13225
0
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13226
0
    const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13227
0
                              __builtin_cpu_supports("avx2") &&
13228
0
                              __builtin_cpu_supports("fma");
13229
0
#endif
13230
13231
    // Iterate over all blocks
13232
0
    for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13233
0
    {
13234
0
        const auto nThisBlockPixelCount =
13235
0
            static_cast<size_t>(window.nXSize) * window.nYSize;
13236
13237
        // Extract pixel values and masks
13238
0
        CPLErr eErr = poDS->RasterIO(
13239
0
            GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13240
0
            adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13241
0
            gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13242
0
            nullptr);
13243
0
        if (eErr == CE_None && bAllBandsSameMask)
13244
0
        {
13245
0
            eErr = apoMaskBands[0]->RasterIO(
13246
0
                GF_Read, window.nXOff, window.nYOff, window.nXSize,
13247
0
                window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13248
0
                window.nYSize, GDT_Byte, 0, 0, nullptr);
13249
0
        }
13250
0
        else
13251
0
        {
13252
0
            for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13253
0
            {
13254
0
                if (apoMaskBands[i])
13255
0
                {
13256
0
                    eErr = apoMaskBands[i]->RasterIO(
13257
0
                        GF_Read, window.nXOff, window.nYOff, window.nXSize,
13258
0
                        window.nYSize, aabyCurBlockMask[i].data(),
13259
0
                        window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13260
0
                }
13261
0
            }
13262
0
        }
13263
0
        if (eErr != CE_None)
13264
0
            return eErr;
13265
13266
        // Compute the mean of all bands for this block
13267
0
        bool bAllBandsAreAllNodata = false;
13268
0
        bool bNoBandHasNodata = false;
13269
0
        for (int i = 0; i < nBandCount; ++i)
13270
0
        {
13271
0
            T dfSum = 0;
13272
0
            size_t nCount = 0;
13273
0
            const T dfNoDataI = adfNoData[i];
13274
0
            const T *padfI =
13275
0
                adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13276
0
#ifdef HAVE_OPENMP_SIMD
13277
0
#pragma omp simd reduction(+ : dfSum)
13278
0
#endif
13279
0
            for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13280
0
            {
13281
0
                const T dfI = padfI[iPixel];
13282
0
                const bool bIsValid =
13283
0
                    !std::isnan(dfI) && dfI != dfNoDataI &&
13284
0
                    (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13285
0
                nCount += bIsValid;
13286
0
                dfSum += bIsValid ? dfI : ZERO;
13287
0
            }
13288
0
            adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13289
0
            anCurBlockCount[i] = nCount;
13290
0
            bAllBandsAreAllNodata =
13291
0
                (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13292
0
            bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13293
0
                               (nCount == nThisBlockPixelCount);
13294
0
        }
13295
13296
        // Modify the pixel values to shift them by minus the mean
13297
0
        if (!bAllBandsAreAllNodata)
13298
0
        {
13299
0
            for (int i = 0; i < nBandCount; ++i)
13300
0
            {
13301
0
                T *padfI =
13302
0
                    adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13303
0
                const T dfMeanI = adfCurBlockMean[i];
13304
0
                for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13305
0
                {
13306
0
                    padfI[iPixel] -= dfMeanI;
13307
0
                }
13308
0
            }
13309
0
        }
13310
13311
        // Update padfComomentMatrix, anCount, adfMean, anCountMean
13312
        // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13313
0
        const auto UpdateGlobalValues =
13314
0
            [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13315
0
             &anCurBlockCount, padfComomentMatrix,
13316
0
             nBandCount](int i, int j, size_t nCount, T dfComoment)
13317
0
        {
13318
0
            const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13319
0
            const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13320
13321
            // Update the total comoment using last formula of paragraph
13322
            // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13323
            // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13324
            //                 (mean_I(A) - mean_I(B)) *
13325
            //                 (mean_J(A) - mean_J(B)) *
13326
            //                 (count(A) * count(B)) / (count(A) + count(B))
13327
            //
13328
            // There might be a small gotcha in the fact that the set of
13329
            // pixels on which the means are computed is not always the
13330
            // same as the the one on which the comoment is computed, if
13331
            // pixels are not valid/invalid at the same indices among bands
13332
            // It is not obvious (to me) what should be the correct behavior.
13333
            // The current approach has the benefit to avoid recomputing
13334
            // the mean for each (i,j) tuple, but only for all i.
13335
0
            if (nCount > 0)
13336
0
            {
13337
0
                padfComomentMatrix[idxInMatrixI] +=
13338
0
                    static_cast<double>(dfComoment);
13339
0
                padfComomentMatrix[idxInMatrixI] +=
13340
0
                    static_cast<double>(adfMean[idxInMatrixI] -
13341
0
                                        adfCurBlockMean[i]) *
13342
0
                    static_cast<double>(adfMean[idxInMatrixJ] -
13343
0
                                        adfCurBlockMean[j]) *
13344
0
                    (static_cast<double>(anCount[idxInMatrixI]) *
13345
0
                     static_cast<double>(nCount) /
13346
0
                     static_cast<double>(anCount[idxInMatrixI] + nCount));
13347
13348
0
                anCount[idxInMatrixI] += nCount;
13349
0
            }
13350
13351
            // Update means
13352
0
            if (anCurBlockCount[i] > 0)
13353
0
            {
13354
0
                adfMean[idxInMatrixI] +=
13355
0
                    (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13356
0
                    static_cast<T>(
13357
0
                        static_cast<double>(anCurBlockCount[i]) /
13358
0
                        static_cast<double>(anCountMean[idxInMatrixI] +
13359
0
                                            anCurBlockCount[i]));
13360
13361
0
                anCountMean[idxInMatrixI] += anCurBlockCount[i];
13362
0
            }
13363
13364
0
            if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13365
0
            {
13366
0
                adfMean[idxInMatrixJ] +=
13367
0
                    (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13368
0
                    static_cast<T>(
13369
0
                        static_cast<double>(anCurBlockCount[j]) /
13370
0
                        static_cast<double>(anCountMean[idxInMatrixJ] +
13371
0
                                            anCurBlockCount[j]));
13372
13373
0
                anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13374
0
            }
13375
0
        };
13376
13377
0
        if (bAllBandsAreAllNodata)
13378
0
        {
13379
            // Optimized code path where all values in the current block
13380
            // are invalid
13381
13382
0
            for (int i = 0; i < nBandCount; ++i)
13383
0
            {
13384
0
                for (int j = i; j < nBandCount; ++j)
13385
0
                {
13386
0
                    UpdateGlobalValues(i, j, 0, ZERO);
13387
0
                }
13388
0
            }
13389
0
        }
13390
0
        else if (bNoBandHasNodata)
13391
0
        {
13392
            // Optimized code path where there are no invalid value in the
13393
            // current block
13394
13395
            if constexpr (!std::is_same_v<T, double>)
13396
            {
13397
                std::fill(aCurBlockComomentMatrix.begin(),
13398
                          aCurBlockComomentMatrix.end(), ZERO);
13399
13400
                GDALMatrixMultiplyAByTransposeAUpperTriangle(
13401
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13402
                    aCurBlockComomentMatrix.data(), nBandCount,
13403
                    nThisBlockPixelCount);
13404
            }
13405
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13406
0
            else if (bHasAVX2_FMA)
13407
0
            {
13408
0
                GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13409
0
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13410
0
                    padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13411
0
            }
13412
0
#endif
13413
0
            else
13414
0
            {
13415
0
                GDALMatrixMultiplyAByTransposeAUpperTriangle(
13416
0
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13417
0
                    padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13418
0
            }
13419
13420
0
            for (int i = 0; i < nBandCount; ++i)
13421
0
            {
13422
0
                for (int j = i; j < nBandCount; ++j)
13423
0
                {
13424
                    if constexpr (!std::is_same_v<T, double>)
13425
                    {
13426
                        const auto idxInMatrixI =
13427
                            static_cast<size_t>(i) * nBandCount + j;
13428
                        UpdateGlobalValues(
13429
                            i, j, nThisBlockPixelCount,
13430
                            aCurBlockComomentMatrix[idxInMatrixI]);
13431
                    }
13432
                    else
13433
0
                    {
13434
0
                        UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13435
0
                    }
13436
0
                }
13437
0
            }
13438
0
        }
13439
0
        else
13440
0
        {
13441
#ifdef HAVE_OPENMP
13442
#pragma omp parallel for schedule(static) num_threads(nNumThreads)
13443
#endif
13444
0
            for (MySignedSize_t k = 0; k < kMax; ++k)
13445
0
            {
13446
0
                int i, j;
13447
0
                std::tie(i, j) = anMapLinearIdxToIJ[k];
13448
13449
                // Now compute the moment of (i, j), but just for this block
13450
0
                size_t nCount = 0;
13451
0
                T dfComoment = 0;
13452
0
                const T *padfI =
13453
0
                    adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13454
0
                const T *padfJ =
13455
0
                    adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13456
13457
                // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13458
                // for the current block
13459
0
                if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13460
0
                     anCurBlockCount[j] == nThisBlockPixelCount) ||
13461
0
                    (bNoneHasMaskOrNodata && bIsAllInteger))
13462
0
                {
13463
                    // Most optimized code path: integer, no nodata, no mask
13464
0
#ifdef HAVE_OPENMP_SIMD
13465
0
#pragma omp simd reduction(+ : dfComoment)
13466
0
#endif
13467
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13468
0
                         ++iPixel)
13469
0
                    {
13470
0
                        dfComoment += padfI[iPixel] * padfJ[iPixel];
13471
0
                    }
13472
0
                    nCount = nThisBlockPixelCount;
13473
0
                }
13474
0
                else if (bNoneHasMaskOrNodata)
13475
0
                {
13476
                    // Floating-point code path with no nodata and no mask
13477
0
#ifdef HAVE_OPENMP_SIMD
13478
0
#pragma omp simd reduction(+ : dfComoment)
13479
0
#endif
13480
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13481
0
                         ++iPixel)
13482
0
                    {
13483
0
                        const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13484
0
                        const bool bIsValid = !std::isnan(dfAcc);
13485
0
                        nCount += bIsValid;
13486
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13487
0
                    }
13488
0
                }
13489
0
                else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13490
0
                {
13491
                    // Code path when there are both nodata values
13492
0
                    const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13493
0
                    const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13494
13495
0
#ifdef HAVE_OPENMP_SIMD
13496
0
#pragma omp simd reduction(+ : dfComoment)
13497
0
#endif
13498
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13499
0
                         ++iPixel)
13500
0
                    {
13501
0
                        const T dfI = padfI[iPixel];
13502
0
                        const T dfJ = padfJ[iPixel];
13503
0
                        const T dfAcc = dfI * dfJ;
13504
0
                        const bool bIsValid = !std::isnan(dfAcc) &&
13505
0
                                              dfI != shiftedNoDataI &&
13506
0
                                              dfJ != shiftedNoDataJ;
13507
0
                        nCount += bIsValid;
13508
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13509
0
                    }
13510
0
                }
13511
0
                else
13512
0
                {
13513
                    // Generic code path
13514
0
                    const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13515
0
                    const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13516
13517
0
#ifdef HAVE_OPENMP_SIMD
13518
0
#pragma omp simd reduction(+ : dfComoment)
13519
0
#endif
13520
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13521
0
                         ++iPixel)
13522
0
                    {
13523
0
                        const T dfI = padfI[iPixel];
13524
0
                        const T dfJ = padfJ[iPixel];
13525
0
                        const T dfAcc = dfI * dfJ;
13526
0
                        const bool bIsValid =
13527
0
                            !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13528
0
                            dfJ != shiftedNoDataJ &&
13529
0
                            (!pabyCurBlockMask[i] ||
13530
0
                             (*pabyCurBlockMask[i])[iPixel]) &&
13531
0
                            (!pabyCurBlockMask[j] ||
13532
0
                             (*pabyCurBlockMask[j])[iPixel]);
13533
0
                        nCount += bIsValid;
13534
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13535
0
                    }
13536
0
                }
13537
13538
0
                UpdateGlobalValues(i, j, nCount, dfComoment);
13539
0
            }
13540
0
        }
13541
13542
0
        ++nCurIter;
13543
0
        if (pfnProgress &&
13544
0
            !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13545
0
                         pProgressData))
13546
0
        {
13547
0
            poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13548
0
                              "User terminated");
13549
0
            return CE_Failure;
13550
0
        }
13551
0
    }
13552
13553
    // Finalize by dividing co-moments by the number of contributing values
13554
    // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13555
0
    for (int i = 0; i < nBandCount; ++i)
13556
0
    {
13557
        // The covariance matrix is symmetric. So start at i
13558
0
        for (int j = i; j < nBandCount; ++j)
13559
0
        {
13560
0
            const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13561
0
            const double dfCovariance =
13562
0
                (nDeltaDegreeOfFreedom < 0 ||
13563
0
                 anCount[idxInMatrixI] <=
13564
0
                     static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13565
0
                    ? std::numeric_limits<double>::quiet_NaN()
13566
0
                    : padfComomentMatrix[idxInMatrixI] /
13567
0
                          static_cast<double>(anCount[idxInMatrixI] -
13568
0
                                              nDeltaDegreeOfFreedom);
13569
13570
0
            padfCovMatrix[idxInMatrixI] = dfCovariance;
13571
            // Fill lower triangle
13572
0
            padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13573
0
                dfCovariance;
13574
0
        }
13575
0
    }
13576
13577
0
    return CE_None;
13578
0
}
13579
13580
/************************************************************************/
13581
/*           GDALDataset::ComputeInterBandCovarianceMatrix()            */
13582
/************************************************************************/
13583
13584
/**
13585
 \brief Compute the covariance matrix between bands of this dataset.
13586
13587
 The covariance indicates the level to which two bands vary together.
13588
13589
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13590
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
13591
13592
 \f[
13593
    \mathrm{cov}[i,j] =
13594
    \frac{
13595
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13596
        \left( v_j[y,x] - \mathrm{mean}_j \right)
13597
    }{
13598
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13599
    }
13600
 \f]
13601
13602
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13603
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13604
 is symmetric.
13605
13606
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13607
 if the pixels in bands are considered to be a sample of the whole population.
13608
 This is consistent with the default of
13609
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13610
 matrix is consistent with what can be obtained with
13611
13612
 \verbatim embed:rst
13613
 .. code-block:: python
13614
13615
     numpy.cov(
13616
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13617
     )
13618
 \endverbatim
13619
13620
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13621
 to be the whole population.
13622
13623
 The caller must provide an already allocated array in padfCovMatrix of size
13624
 at least nBandCount * nBandCount.
13625
13626
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13627
 metadata items are available in bands. See GetInterBandCovarianceMatrix()
13628
 to use them.
13629
13630
 The implementation is optimized to minimize the amount of pixel reading.
13631
13632
 This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13633
13634
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13635
                      nBandCount * nBandCount.
13636
 @param nSize Number of elements in output array.
13637
 @param nBandCount Zero for all bands, or number of values in panBandList.
13638
                   Defaults to 0.
13639
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
13640
                    nBandCount values such as panBandList[i] is the index
13641
                    between 1 and GetRasterCount() of a band that must be used
13642
                    in the covariance computation. Defaults to nullptr.
13643
 @param bApproxOK Whether it is acceptable to use a subsample of values.
13644
                  Defaults to false.
13645
 @param bWriteIntoMetadata Whether this method must write
13646
                           STATISTICS_COVARIANCES band metadata items.
13647
                           Defaults to true.
13648
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13649
                              averaging phase of the covariance computation.
13650
                              Defaults to 1.
13651
 @param pfnProgress a function to call to report progress, or NULL.
13652
 @param pProgressData application data to pass to the progress function.
13653
13654
 @return CE_None if successful, or CE_Failure in case of failure
13655
13656
 @since 3.13
13657
13658
 @see GetInterBandCovarianceMatrix()
13659
 */
13660
CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13661
    double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13662
    bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13663
    GDALProgressFunc pfnProgress, void *pProgressData)
13664
0
{
13665
0
    std::vector<int> anBandListTmp;  // keep in this scope
13666
0
    if (nBandCount == 0)
13667
0
    {
13668
0
        if (nBands == 0)
13669
0
            return CE_None;
13670
0
        for (int i = 0; i < nBands; ++i)
13671
0
            anBandListTmp.push_back(i + 1);
13672
0
        nBandCount = nBands;
13673
0
        panBandList = anBandListTmp.data();
13674
0
    }
13675
0
    else
13676
0
    {
13677
0
        if (nBandCount > nBands)
13678
0
        {
13679
0
            CPLError(CE_Failure, CPLE_AppDefined,
13680
0
                     "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13681
0
            return CE_Failure;
13682
0
        }
13683
0
        for (int i = 0; i < nBandCount; ++i)
13684
0
        {
13685
0
            if (panBandList[i] <= 0 || panBandList[i] > nBands)
13686
0
            {
13687
0
                CPLError(CE_Failure, CPLE_AppDefined,
13688
0
                         "ComputeInterBandCovarianceMatrix(): invalid value "
13689
0
                         "panBandList[%d] = %d",
13690
0
                         i, panBandList[i]);
13691
0
                return CE_Failure;
13692
0
            }
13693
0
        }
13694
13695
0
        if (bWriteIntoMetadata)
13696
0
        {
13697
0
            bool bOK = nBandCount == nBands;
13698
0
            for (int i = 0; bOK && i < nBandCount; ++i)
13699
0
            {
13700
0
                bOK = (panBandList[i] == i + 1);
13701
0
            }
13702
0
            if (!bOK)
13703
0
            {
13704
0
                CPLError(CE_Failure, CPLE_AppDefined,
13705
0
                         "ComputeInterBandCovarianceMatrix(): cannot write "
13706
0
                         "STATISTICS_COVARIANCES metadata since the input band "
13707
0
                         "list is not [1, 2, ... GetRasterCount()]");
13708
0
                return CE_Failure;
13709
0
            }
13710
0
        }
13711
0
    }
13712
13713
0
    const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13714
0
    if (nSize < nMatrixSize)
13715
0
    {
13716
0
        CPLError(CE_Failure, CPLE_AppDefined,
13717
0
                 "ComputeInterBandCovarianceMatrix(): too small result matrix "
13718
0
                 "provided");
13719
0
        return CE_Failure;
13720
0
    }
13721
13722
    // Find appropriate overview dataset
13723
0
    GDALDataset *poActiveDS = this;
13724
0
    if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13725
0
    {
13726
0
        GDALDataset *poOvrDS = nullptr;
13727
0
        for (int i = 0; i < nBandCount; ++i)
13728
0
        {
13729
0
            const int nIdxBand = panBandList[i] - 1;
13730
0
            auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13731
0
                GDALSTAT_APPROX_NUMSAMPLES);
13732
13733
0
            if (poOvrBand == papoBands[i] ||
13734
0
                poOvrBand->GetBand() != panBandList[i])
13735
0
            {
13736
0
                poOvrDS = nullptr;
13737
0
                break;
13738
0
            }
13739
0
            else if (i == 0)
13740
0
            {
13741
0
                if (poOvrBand->GetDataset() == this)
13742
0
                {
13743
0
                    break;
13744
0
                }
13745
0
                poOvrDS = poOvrBand->GetDataset();
13746
0
            }
13747
0
            else if (poOvrBand->GetDataset() != poOvrDS)
13748
0
            {
13749
0
                poOvrDS = nullptr;
13750
0
                break;
13751
0
            }
13752
0
        }
13753
0
        if (poOvrDS)
13754
0
        {
13755
0
            poActiveDS = poOvrDS;
13756
0
        }
13757
0
    }
13758
13759
#ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13760
    const auto UseFloat32 = [](GDALDataType eDT)
13761
    {
13762
        return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13763
               eDT == GDT_Int16 || eDT == GDT_Float32;
13764
    };
13765
13766
    bool bUseFloat32 = UseFloat32(
13767
        poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13768
    for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13769
    {
13770
        bUseFloat32 = UseFloat32(
13771
            poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13772
    }
13773
#endif
13774
13775
0
    CPLErr eErr =
13776
#ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13777
        bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13778
                          poActiveDS, padfCovMatrix, nBandCount, panBandList,
13779
                          poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13780
                          pfnProgress, pProgressData)
13781
                    :
13782
#endif
13783
0
                    ComputeInterBandCovarianceMatrixInternal<double>(
13784
0
                        poActiveDS, padfCovMatrix, nBandCount, panBandList,
13785
0
                        poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13786
0
                        pfnProgress, pProgressData);
13787
13788
0
    if (bWriteIntoMetadata && eErr == CE_None)
13789
0
    {
13790
0
        CPLAssert(nBands == nBandCount);
13791
0
        std::string osStr;
13792
0
        size_t idx = 0;
13793
0
        for (int i = 0; i < nBands; ++i)
13794
0
        {
13795
0
            osStr.clear();
13796
0
            for (int j = 0; j < nBands; ++j, ++idx)
13797
0
            {
13798
0
                if (j > 0)
13799
0
                    osStr += ',';
13800
0
                osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13801
0
            }
13802
0
            papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13803
0
                                          osStr.c_str());
13804
0
        }
13805
0
    }
13806
13807
0
    return eErr;
13808
0
}
13809
13810
/************************************************************************/
13811
/*            GDALDatasetComputeInterBandCovarianceMatrix()             */
13812
/************************************************************************/
13813
13814
/**
13815
 \brief Compute the covariance matrix between bands of this dataset.
13816
13817
 The covariance indicates the level to which two bands vary together.
13818
13819
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13820
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
13821
13822
 \f[
13823
    \mathrm{cov}[i,j] =
13824
    \frac{
13825
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13826
        \left( v_j[y,x] - \mathrm{mean}_j \right)
13827
    }{
13828
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13829
    }
13830
 \f]
13831
13832
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13833
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13834
 is symmetric.
13835
13836
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13837
 if the pixels in bands are considered to be a sample of the whole population.
13838
 This is consistent with the default of
13839
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13840
 matrix is consistent with what can be obtained with
13841
13842
 \verbatim embed:rst
13843
 .. code-block:: python
13844
13845
     numpy.cov(
13846
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13847
     )
13848
 \endverbatim
13849
13850
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13851
 to be the whole population.
13852
13853
 The caller must provide an already allocated array in padfCovMatrix of size
13854
 at least GDALGetRasterCount() * GDALGetRasterCount().
13855
13856
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13857
 metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13858
 to use them.
13859
13860
 This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13861
13862
 @param hDS Dataset handle.
13863
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13864
                      nBandCount * nBandCount.
13865
 @param nSize Number of elements in output array.
13866
 @param nBandCount Zero for all bands, or number of values in panBandList.
13867
                   Defaults to 0.
13868
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
13869
                    nBandCount values such as panBandList[i] is the index
13870
                    between 1 and GetRasterCount() of a band that must be used
13871
                    in the covariance computation. Defaults to nullptr.
13872
 @param bApproxOK Whether it is acceptable to use a subsample of values.
13873
                  Defaults to false.
13874
 @param bWriteIntoMetadata Whether this method must write
13875
                           STATISTICS_COVARIANCES band metadata items.
13876
                           Defaults to true.
13877
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13878
                              averaging phase of the covariance computation.
13879
                              Defaults to 1.
13880
 @param pfnProgress a function to call to report progress, or NULL.
13881
 @param pProgressData application data to pass to the progress function.
13882
13883
 @return CE_None if successful, or CE_Failure in case of failure
13884
13885
 @since 3.13
13886
13887
 @see GDALDatasetGetInterBandCovarianceMatrix()
13888
 */
13889
CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13890
    GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13891
    const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13892
    int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13893
    void *pProgressData)
13894
0
{
13895
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13896
0
    VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13897
0
    return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13898
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13899
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13900
0
}