Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdaldriver.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Implementation of GDALDriver class (and C wrappers)
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1998, 2000, Frank Warmerdam
9
 * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "gdal.h"
16
#include "gdal_priv.h"
17
#include "gdal_rat.h"
18
#include "gdalalgorithm.h"
19
#include "gdal_known_connection_prefixes.h"
20
21
#include <algorithm>
22
#include <cerrno>
23
#include <cstdlib>
24
#include <cstring>
25
#include <set>
26
#include <sys/stat.h>
27
28
#include "cpl_conv.h"
29
#include "cpl_error.h"
30
#include "cpl_minixml.h"
31
#include "cpl_multiproc.h"
32
#include "cpl_progress.h"
33
#include "cpl_string.h"
34
#include "cpl_vsi.h"
35
#include "ograpispy.h"
36
#include "ogr_core.h"
37
#include "ogrsf_frmts.h"
38
39
/************************************************************************/
40
/*                             GDALDriver()                             */
41
/************************************************************************/
42
43
0
GDALDriver::GDALDriver() = default;
44
45
/************************************************************************/
46
/*                            ~GDALDriver()                             */
47
/************************************************************************/
48
49
GDALDriver::~GDALDriver()
50
51
0
{
52
0
    if (pfnUnloadDriver != nullptr)
53
0
        pfnUnloadDriver(this);
54
0
}
55
56
/************************************************************************/
57
/*                          GDALCreateDriver()                          */
58
/************************************************************************/
59
60
/**
61
 * \brief Create a GDALDriver.
62
 *
63
 * Creates a driver in the GDAL heap.
64
 */
65
66
GDALDriverH CPL_STDCALL GDALCreateDriver()
67
0
{
68
0
    return new GDALDriver();
69
0
}
70
71
/************************************************************************/
72
/*                         GDALDestroyDriver()                          */
73
/************************************************************************/
74
75
/**
76
 * \brief Destroy a GDALDriver.
77
 *
78
 * This is roughly equivalent to deleting the driver, but is guaranteed
79
 * to take place in the GDAL heap.  It is important this that function
80
 * not be called on a driver that is registered with the GDALDriverManager.
81
 *
82
 * @param hDriver the driver to destroy.
83
 */
84
85
void CPL_STDCALL GDALDestroyDriver(GDALDriverH hDriver)
86
87
0
{
88
0
    if (hDriver != nullptr)
89
0
        delete GDALDriver::FromHandle(hDriver);
90
0
}
91
92
/************************************************************************/
93
/*                                Open()                                */
94
/************************************************************************/
95
96
//! @cond Doxygen_Suppress
97
98
GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
99
0
{
100
101
0
    GDALDataset *poDS = nullptr;
102
0
    pfnOpen = GetOpenCallback();
103
0
    if (pfnOpen != nullptr)
104
0
    {
105
0
        poDS = pfnOpen(poOpenInfo);
106
0
    }
107
0
    else if (pfnOpenWithDriverArg != nullptr)
108
0
    {
109
0
        poDS = pfnOpenWithDriverArg(this, poOpenInfo);
110
0
    }
111
112
0
    if (poDS)
113
0
    {
114
        // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
115
        // poDS->nOpenFlags
116
0
        int nOpenFlags = poOpenInfo->nOpenFlags &
117
0
                         ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
118
0
        if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
119
0
            nOpenFlags |= GDAL_OF_THREAD_SAFE;
120
0
        poDS->nOpenFlags = nOpenFlags;
121
122
0
        if (strlen(poDS->GetDescription()) == 0)
123
0
            poDS->SetDescription(poOpenInfo->pszFilename);
124
125
0
        if (poDS->poDriver == nullptr)
126
0
            poDS->poDriver = this;
127
128
0
        if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
129
0
        {
130
0
            poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
131
0
        }
132
133
0
        if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
134
0
        {
135
0
            if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
136
0
                CPLDebug(
137
0
                    "GDAL",
138
0
                    "GDALOpen(%s, this=%p) succeeds as "
139
0
                    "%s (pid=%d, responsiblePID=%d).",
140
0
                    poOpenInfo->pszFilename, poDS, GetDescription(),
141
0
                    static_cast<int>(CPLGetPID()),
142
0
                    static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
143
0
            else
144
0
                CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
145
0
                         poOpenInfo->pszFilename, poDS, GetDescription());
146
147
0
            poDS->AddToDatasetOpenList();
148
0
        }
149
0
    }
150
151
0
    return poDS;
152
0
}
153
154
//! @endcond
155
156
/************************************************************************/
157
/*                               Create()                               */
158
/************************************************************************/
159
160
/**
161
 * \brief Create a new dataset with this driver.
162
 *
163
 * What argument values are legal for particular drivers is driver specific,
164
 * and there is no way to query in advance to establish legal values.
165
 *
166
 * That function will try to validate the creation option list passed to the
167
 * driver with the GDALValidateCreationOptions() method. This check can be
168
 * disabled by defining the configuration option
169
 * GDAL_VALIDATE_CREATION_OPTIONS=NO.
170
 *
171
 * After you have finished working with the returned dataset, it is
172
 * <b>required</b> to close it with GDALClose(). This does not only close the
173
 * file handle, but also ensures that all the data and metadata has been written
174
 * to the dataset (GDALFlushCache() is not sufficient for that purpose).
175
 *
176
 * The arguments nXSize, nYSize and nBands can be passed to 0 when
177
 * creating a vector-only dataset for a compatible driver.
178
 *
179
 * Equivalent of the C function GDALCreate().
180
 *
181
 * @param pszFilename the name of the dataset to create.  UTF-8 encoded.
182
 * @param nXSize width of created raster in pixels.
183
 * @param nYSize height of created raster in pixels.
184
 * @param nBands number of bands.
185
 * @param eType type of raster.
186
 * @param papszOptions list of driver specific control parameters.
187
 * The APPEND_SUBDATASET=YES option can be
188
 * specified to avoid prior destruction of existing dataset.
189
 *
190
 * @return NULL on failure, or a new GDALDataset.
191
 */
192
193
GDALDataset *GDALDriver::Create(const char *pszFilename, int nXSize, int nYSize,
194
                                int nBands, GDALDataType eType,
195
                                CSLConstList papszOptions)
196
197
0
{
198
    /* -------------------------------------------------------------------- */
199
    /*      Does this format support creation.                              */
200
    /* -------------------------------------------------------------------- */
201
0
    pfnCreate = GetCreateCallback();
202
0
    if (CPL_UNLIKELY(pfnCreate == nullptr && pfnCreateEx == nullptr &&
203
0
                     pfnCreateVectorOnly == nullptr))
204
0
    {
205
0
        CPLError(CE_Failure, CPLE_NotSupported,
206
0
                 "GDALDriver::Create() ... no create method implemented"
207
0
                 " for this format.");
208
209
0
        return nullptr;
210
0
    }
211
    /* -------------------------------------------------------------------- */
212
    /*      Do some rudimentary argument checking.                          */
213
    /* -------------------------------------------------------------------- */
214
0
    if (CPL_UNLIKELY(nBands < 0))
215
0
    {
216
0
        CPLError(CE_Failure, CPLE_AppDefined,
217
0
                 "Attempt to create dataset with %d bands is illegal,"
218
0
                 "Must be >= 0.",
219
0
                 nBands);
220
0
        return nullptr;
221
0
    }
222
223
0
    if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
224
0
                     GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
225
0
                     (nXSize < 1 || nYSize < 1)))
226
0
    {
227
0
        CPLError(CE_Failure, CPLE_AppDefined,
228
0
                 "Attempt to create %dx%d dataset is illegal,"
229
0
                 "sizes must be larger than zero.",
230
0
                 nXSize, nYSize);
231
0
        return nullptr;
232
0
    }
233
234
0
    if (CPL_UNLIKELY(nBands != 0 &&
235
0
                     (eType == GDT_Unknown || eType == GDT_TypeCount)))
236
0
    {
237
0
        CPLError(CE_Failure, CPLE_IllegalArg,
238
0
                 "Illegal GDT_Unknown/GDT_TypeCount argument");
239
0
        return nullptr;
240
0
    }
241
242
    /* -------------------------------------------------------------------- */
243
    /*      Make sure we cleanup if there is an existing dataset of this    */
244
    /*      name.  But even if that seems to fail we will continue since    */
245
    /*      it might just be a corrupt file or something.                   */
246
    /* -------------------------------------------------------------------- */
247
0
    if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
248
0
    {
249
        // Someone issuing Create("foo.tif") on a
250
        // memory driver doesn't expect files with those names to be deleted
251
        // on a file system...
252
        // This is somewhat messy. Ideally there should be a way for the
253
        // driver to overload the default behavior
254
0
        if (!EQUAL(GetDescription(), "MEM") &&
255
0
            !EQUAL(GetDescription(), "Memory") &&
256
            // ogr2ogr -f PostgreSQL might reach the Delete method of the
257
            // PostgisRaster driver which is undesirable
258
0
            !EQUAL(GetDescription(), "PostgreSQL"))
259
0
        {
260
0
            QuietDelete(pszFilename);
261
0
        }
262
0
    }
263
264
    /* -------------------------------------------------------------------- */
265
    /*      Validate creation options.                                      */
266
    /* -------------------------------------------------------------------- */
267
0
    if (CPLTestBool(
268
0
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
269
0
        GDALValidateCreationOptions(this, papszOptions);
270
271
    /* -------------------------------------------------------------------- */
272
    /*      Proceed with creation.                                          */
273
    /* -------------------------------------------------------------------- */
274
0
    CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
275
0
             GetDescription(), pszFilename, nXSize, nYSize, nBands,
276
0
             GDALGetDataTypeName(eType), papszOptions);
277
278
0
    GDALDataset *poDS = nullptr;
279
0
    if (pfnCreateEx != nullptr)
280
0
    {
281
0
        poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
282
0
                           const_cast<char **>(papszOptions));
283
0
    }
284
0
    else if (pfnCreate != nullptr)
285
0
    {
286
0
        poDS = pfnCreate(pszFilename, nXSize, nYSize, nBands, eType,
287
0
                         const_cast<char **>(papszOptions));
288
0
    }
289
0
    else if (nBands < 1)
290
0
    {
291
0
        poDS = pfnCreateVectorOnly(this, pszFilename,
292
0
                                   const_cast<char **>(papszOptions));
293
0
    }
294
295
0
    if (poDS != nullptr)
296
0
    {
297
0
        if (poDS->GetDescription() == nullptr ||
298
0
            strlen(poDS->GetDescription()) == 0)
299
0
            poDS->SetDescription(pszFilename);
300
301
0
        if (poDS->poDriver == nullptr)
302
0
            poDS->poDriver = this;
303
304
0
        poDS->AddToDatasetOpenList();
305
0
    }
306
307
0
    return poDS;
308
0
}
309
310
/************************************************************************/
311
/*                             GDALCreate()                             */
312
/************************************************************************/
313
314
/**
315
 * \brief Create a new dataset with this driver.
316
 *
317
 * @see GDALDriver::Create()
318
 */
319
320
GDALDatasetH CPL_DLL CPL_STDCALL GDALCreate(GDALDriverH hDriver,
321
                                            const char *pszFilename, int nXSize,
322
                                            int nYSize, int nBands,
323
                                            GDALDataType eBandType,
324
                                            CSLConstList papszOptions)
325
326
0
{
327
0
    VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
328
329
0
    GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
330
0
        pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
331
332
0
#ifdef OGRAPISPY_ENABLED
333
0
    if (nBands < 1)
334
0
    {
335
0
        OGRAPISpyCreateDataSource(hDriver, pszFilename,
336
0
                                  const_cast<char **>(papszOptions), hDS);
337
0
    }
338
0
#endif
339
340
0
    return hDS;
341
0
}
342
343
/************************************************************************/
344
/*                       CreateMultiDimensional()                       */
345
/************************************************************************/
346
347
/**
348
 * \brief Create a new multidimensional dataset with this driver.
349
 *
350
 * Only drivers that advertise the GDAL_DCAP_MULTIDIM_RASTER capability and
351
 * implement the pfnCreateMultiDimensional method might return a non nullptr
352
 * GDALDataset.
353
 *
354
 * This is the same as the C function GDALCreateMultiDimensional().
355
 *
356
 * @param pszFilename  the name of the dataset to create.  UTF-8 encoded.
357
 * @param papszRootGroupOptions driver specific options regarding the creation
358
 *                              of the root group. Might be nullptr.
359
 * @param papszOptions driver specific options regarding the creation
360
 *                     of the dataset. Might be nullptr.
361
 * @return a new dataset, or nullptr in case of failure.
362
 *
363
 * @since GDAL 3.1
364
 */
365
366
GDALDataset *
367
GDALDriver::CreateMultiDimensional(const char *pszFilename,
368
                                   CSLConstList papszRootGroupOptions,
369
                                   CSLConstList papszOptions)
370
371
0
{
372
    /* -------------------------------------------------------------------- */
373
    /*      Does this format support creation.                              */
374
    /* -------------------------------------------------------------------- */
375
0
    pfnCreateMultiDimensional = GetCreateMultiDimensionalCallback();
376
0
    if (pfnCreateMultiDimensional == nullptr)
377
0
    {
378
0
        CPLError(CE_Failure, CPLE_NotSupported,
379
0
                 "GDALDriver::CreateMultiDimensional() ... "
380
0
                 "no CreateMultiDimensional method implemented "
381
0
                 "for this format.");
382
383
0
        return nullptr;
384
0
    }
385
386
    /* -------------------------------------------------------------------- */
387
    /*      Validate creation options.                                      */
388
    /* -------------------------------------------------------------------- */
389
0
    if (CPLTestBool(
390
0
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
391
0
    {
392
0
        const char *pszOptionList =
393
0
            GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
394
0
        CPLString osDriver;
395
0
        osDriver.Printf("driver %s", GetDescription());
396
0
        GDALValidateOptions(pszOptionList, papszOptions, "creation option",
397
0
                            osDriver);
398
0
    }
399
400
0
    auto poDstDS = pfnCreateMultiDimensional(pszFilename, papszRootGroupOptions,
401
0
                                             papszOptions);
402
403
0
    if (poDstDS != nullptr)
404
0
    {
405
0
        if (poDstDS->GetDescription() == nullptr ||
406
0
            strlen(poDstDS->GetDescription()) == 0)
407
0
            poDstDS->SetDescription(pszFilename);
408
409
0
        if (poDstDS->poDriver == nullptr)
410
0
            poDstDS->poDriver = this;
411
0
    }
412
413
0
    return poDstDS;
414
0
}
415
416
/************************************************************************/
417
/*                     GDALCreateMultiDimensional()                     */
418
/************************************************************************/
419
420
/** \brief Create a new multidimensional dataset with this driver.
421
 *
422
 * This is the same as the C++ method GDALDriver::CreateMultiDimensional().
423
 */
424
GDALDatasetH GDALCreateMultiDimensional(GDALDriverH hDriver,
425
                                        const char *pszName,
426
                                        CSLConstList papszRootGroupOptions,
427
                                        CSLConstList papszOptions)
428
0
{
429
0
    VALIDATE_POINTER1(hDriver, __func__, nullptr);
430
0
    VALIDATE_POINTER1(pszName, __func__, nullptr);
431
0
    return GDALDataset::ToHandle(
432
0
        GDALDriver::FromHandle(hDriver)->CreateMultiDimensional(
433
0
            pszName, papszRootGroupOptions, papszOptions));
434
0
}
435
436
/************************************************************************/
437
/*                 DefaultCreateCopyMultiDimensional()                  */
438
/************************************************************************/
439
440
//! @cond Doxygen_Suppress
441
442
CPLErr GDALDriver::DefaultCreateCopyMultiDimensional(
443
    GDALDataset *poSrcDS, GDALDataset *poDstDS, bool bStrict,
444
    CSLConstList papszOptions, GDALProgressFunc pfnProgress,
445
    void *pProgressData)
446
0
{
447
0
    if (pfnProgress == nullptr)
448
0
        pfnProgress = GDALDummyProgress;
449
450
0
    auto poSrcRG = poSrcDS->GetRootGroup();
451
0
    if (!poSrcRG)
452
0
        return CE_Failure;
453
0
    auto poDstRG = poDstDS->GetRootGroup();
454
0
    if (!poDstRG)
455
0
        return CE_Failure;
456
0
    GUInt64 nCurCost = 0;
457
0
    return poDstRG->CopyFrom(poDstRG, poSrcDS, poSrcRG, bStrict, nCurCost,
458
0
                             poSrcRG->GetTotalCopyCost(), pfnProgress,
459
0
                             pProgressData, papszOptions)
460
0
               ? CE_None
461
0
               : CE_Failure;
462
0
}
463
464
//! @endcond
465
466
/************************************************************************/
467
/*                          DefaultCopyMasks()                          */
468
/************************************************************************/
469
470
//! @cond Doxygen_Suppress
471
CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
472
                                    int bStrict)
473
474
0
{
475
0
    return DefaultCopyMasks(poSrcDS, poDstDS, bStrict, nullptr, nullptr,
476
0
                            nullptr);
477
0
}
478
479
CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
480
                                    int bStrict, CSLConstList /*papszOptions*/,
481
                                    GDALProgressFunc pfnProgress,
482
                                    void *pProgressData)
483
484
0
{
485
0
    if (pfnProgress == nullptr)
486
0
        pfnProgress = GDALDummyProgress;
487
488
0
    int nBands = poSrcDS->GetRasterCount();
489
0
    if (nBands == 0)
490
0
        return CE_None;
491
492
    /* -------------------------------------------------------------------- */
493
    /*      Try to copy mask if it seems appropriate.                       */
494
    /* -------------------------------------------------------------------- */
495
0
    const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
496
0
    CPLErr eErr = CE_None;
497
498
0
    int nTotalBandsWithMask = 0;
499
0
    for (int iBand = 0; iBand < nBands; ++iBand)
500
0
    {
501
0
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
502
503
0
        int nMaskFlags = poSrcBand->GetMaskFlags();
504
0
        if (!(nMaskFlags &
505
0
              (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
506
0
        {
507
0
            nTotalBandsWithMask++;
508
0
        }
509
0
    }
510
511
0
    int iBandWithMask = 0;
512
0
    for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
513
0
    {
514
0
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
515
516
0
        int nMaskFlags = poSrcBand->GetMaskFlags();
517
0
        if (eErr == CE_None && !(nMaskFlags & (GMF_ALL_VALID | GMF_PER_DATASET |
518
0
                                               GMF_ALPHA | GMF_NODATA)))
519
0
        {
520
0
            GDALRasterBand *poDstBand = poDstDS->GetRasterBand(iBand + 1);
521
0
            if (poDstBand != nullptr)
522
0
            {
523
0
                eErr = poDstBand->CreateMaskBand(nMaskFlags);
524
0
                if (eErr == CE_None)
525
0
                {
526
0
                    void *pScaledData = GDALCreateScaledProgress(
527
0
                        double(iBandWithMask) /
528
0
                            std::max(1, nTotalBandsWithMask),
529
0
                        double(iBandWithMask + 1) /
530
0
                            std::max(1, nTotalBandsWithMask),
531
0
                        pfnProgress, pProgressData);
532
0
                    eErr = GDALRasterBandCopyWholeRaster(
533
0
                        poSrcBand->GetMaskBand(), poDstBand->GetMaskBand(),
534
0
                        papszOptions, GDALScaledProgress, pScaledData);
535
0
                    GDALDestroyScaledProgress(pScaledData);
536
0
                }
537
0
                else if (!bStrict)
538
0
                {
539
0
                    eErr = CE_None;
540
0
                }
541
0
            }
542
0
        }
543
0
    }
544
545
    /* -------------------------------------------------------------------- */
546
    /*      Try to copy a per-dataset mask if we have one.                  */
547
    /* -------------------------------------------------------------------- */
548
0
    const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
549
0
    if (eErr == CE_None &&
550
0
        !(nMaskFlags & (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) &&
551
0
        (nMaskFlags & GMF_PER_DATASET))
552
0
    {
553
0
        eErr = poDstDS->CreateMaskBand(nMaskFlags);
554
0
        if (eErr == CE_None)
555
0
        {
556
0
            eErr = GDALRasterBandCopyWholeRaster(
557
0
                poSrcDS->GetRasterBand(1)->GetMaskBand(),
558
0
                poDstDS->GetRasterBand(1)->GetMaskBand(), papszOptions,
559
0
                pfnProgress, pProgressData);
560
0
        }
561
0
        else if (!bStrict)
562
0
        {
563
0
            eErr = CE_None;
564
0
        }
565
0
    }
566
567
0
    return eErr;
568
0
}
569
570
/************************************************************************/
571
/*                         DefaultCreateCopy()                          */
572
/************************************************************************/
573
574
GDALDataset *GDALDriver::DefaultCreateCopy(const char *pszFilename,
575
                                           GDALDataset *poSrcDS, int bStrict,
576
                                           CSLConstList papszOptions,
577
                                           GDALProgressFunc pfnProgress,
578
                                           void *pProgressData)
579
580
0
{
581
0
    if (pfnProgress == nullptr)
582
0
        pfnProgress = GDALDummyProgress;
583
584
0
    CPLErrorReset();
585
586
    /* -------------------------------------------------------------------- */
587
    /*      Use multidimensional raster API if available.                   */
588
    /* -------------------------------------------------------------------- */
589
0
    auto poSrcGroup = poSrcDS->GetRootGroup();
590
0
    if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
591
0
    {
592
0
        CPLStringList aosDatasetCO;
593
0
        for (const char *pszOption : cpl::Iterate(papszOptions))
594
0
        {
595
0
            if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
596
0
                aosDatasetCO.AddString(pszOption);
597
0
        }
598
0
        auto poDstDS = std::unique_ptr<GDALDataset>(
599
0
            CreateMultiDimensional(pszFilename, nullptr, aosDatasetCO.List()));
600
0
        if (!poDstDS)
601
0
            return nullptr;
602
0
        auto poDstGroup = poDstDS->GetRootGroup();
603
0
        if (!poDstGroup)
604
0
            return nullptr;
605
0
        if (DefaultCreateCopyMultiDimensional(
606
0
                poSrcDS, poDstDS.get(), CPL_TO_BOOL(bStrict), papszOptions,
607
0
                pfnProgress, pProgressData) != CE_None)
608
0
            return nullptr;
609
0
        return poDstDS.release();
610
0
    }
611
612
    /* -------------------------------------------------------------------- */
613
    /*      Validate that we can create the output as requested.            */
614
    /* -------------------------------------------------------------------- */
615
0
    const int nXSize = poSrcDS->GetRasterXSize();
616
0
    const int nYSize = poSrcDS->GetRasterYSize();
617
0
    const int nBands = poSrcDS->GetRasterCount();
618
619
0
    CPLDebug("GDAL", "Using default GDALDriver::CreateCopy implementation.");
620
621
0
    const int nLayerCount = poSrcDS->GetLayerCount();
622
0
    if (nBands == 0 && nLayerCount == 0 &&
623
0
        GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
624
0
    {
625
0
        CPLError(CE_Failure, CPLE_NotSupported,
626
0
                 "GDALDriver::DefaultCreateCopy does not support zero band");
627
0
        return nullptr;
628
0
    }
629
0
    if (poSrcDS->GetDriver() != nullptr &&
630
0
        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
631
0
        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
632
0
        GetMetadataItem(GDAL_DCAP_RASTER) == nullptr &&
633
0
        GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr)
634
0
    {
635
0
        CPLError(CE_Failure, CPLE_NotSupported,
636
0
                 "Source driver is raster-only whereas output driver is "
637
0
                 "vector-only");
638
0
        return nullptr;
639
0
    }
640
0
    else if (poSrcDS->GetDriver() != nullptr &&
641
0
             poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) ==
642
0
                 nullptr &&
643
0
             poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) !=
644
0
                 nullptr &&
645
0
             GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
646
0
             GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
647
0
    {
648
0
        CPLError(CE_Failure, CPLE_NotSupported,
649
0
                 "Source driver is vector-only whereas output driver is "
650
0
                 "raster-only");
651
0
        return nullptr;
652
0
    }
653
654
0
    if (!pfnProgress(0.0, nullptr, pProgressData))
655
0
    {
656
0
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
657
0
        return nullptr;
658
0
    }
659
660
    /* -------------------------------------------------------------------- */
661
    /*      Propagate some specific structural metadata as options if it    */
662
    /*      appears to be supported by the target driver and the caller     */
663
    /*      didn't provide values.                                          */
664
    /* -------------------------------------------------------------------- */
665
0
    char **papszCreateOptions = CSLDuplicate(papszOptions);
666
0
    const char *const apszOptItems[] = {"NBITS", "IMAGE_STRUCTURE", "PIXELTYPE",
667
0
                                        "IMAGE_STRUCTURE", nullptr};
668
669
0
    for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
670
0
         iOptItem += 2)
671
0
    {
672
        // does the source have this metadata item on the first band?
673
0
        auto poBand = poSrcDS->GetRasterBand(1);
674
0
        poBand->EnablePixelTypeSignedByteWarning(false);
675
0
        const char *pszValue = poBand->GetMetadataItem(
676
0
            apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
677
0
        poBand->EnablePixelTypeSignedByteWarning(true);
678
679
0
        if (pszValue == nullptr)
680
0
            continue;
681
682
        // Do not override provided value.
683
0
        if (CSLFetchNameValue(papszCreateOptions, pszValue) != nullptr)
684
0
            continue;
685
686
        // Does this appear to be a supported creation option on this driver?
687
0
        const char *pszOptionList =
688
0
            GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
689
690
0
        if (pszOptionList == nullptr ||
691
0
            strstr(pszOptionList, apszOptItems[iOptItem]) == nullptr)
692
0
            continue;
693
694
0
        papszCreateOptions = CSLSetNameValue(papszCreateOptions,
695
0
                                             apszOptItems[iOptItem], pszValue);
696
0
    }
697
698
    /* -------------------------------------------------------------------- */
699
    /*      Create destination dataset.                                     */
700
    /* -------------------------------------------------------------------- */
701
0
    GDALDataType eType = GDT_Unknown;
702
703
0
    if (nBands > 0)
704
0
        eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
705
0
    GDALDataset *poDstDS =
706
0
        Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
707
708
0
    CSLDestroy(papszCreateOptions);
709
710
0
    if (poDstDS == nullptr)
711
0
        return nullptr;
712
713
0
    int nDstBands = poDstDS->GetRasterCount();
714
0
    CPLErr eErr = CE_None;
715
0
    if (nDstBands != nBands)
716
0
    {
717
0
        if (GetMetadataItem(GDAL_DCAP_RASTER) != nullptr)
718
0
        {
719
            // Should not happen for a well-behaved driver.
720
0
            CPLError(
721
0
                CE_Failure, CPLE_AppDefined,
722
0
                "Output driver created only %d bands whereas %d were expected",
723
0
                nDstBands, nBands);
724
0
            eErr = CE_Failure;
725
0
        }
726
0
        nDstBands = 0;
727
0
    }
728
729
    /* -------------------------------------------------------------------- */
730
    /*      Try setting the projection and geotransform if it seems         */
731
    /*      suitable.                                                       */
732
    /* -------------------------------------------------------------------- */
733
0
    if (nDstBands == 0 && !bStrict)
734
0
        CPLTurnFailureIntoWarning(true);
735
736
0
    GDALGeoTransform gt;
737
0
    if (eErr == CE_None && poSrcDS->GetGeoTransform(gt) == CE_None &&
738
0
        gt != GDALGeoTransform())
739
0
    {
740
0
        eErr = poDstDS->SetGeoTransform(gt);
741
0
        if (!bStrict)
742
0
            eErr = CE_None;
743
0
    }
744
745
0
    if (eErr == CE_None)
746
0
    {
747
0
        const auto poSrcSRS = poSrcDS->GetSpatialRefRasterOnly();
748
0
        if (poSrcSRS && !poSrcSRS->IsEmpty())
749
0
        {
750
0
            eErr = poDstDS->SetSpatialRef(poSrcSRS);
751
0
            if (!bStrict)
752
0
                eErr = CE_None;
753
0
        }
754
0
    }
755
756
    /* -------------------------------------------------------------------- */
757
    /*      Copy GCPs.                                                      */
758
    /* -------------------------------------------------------------------- */
759
0
    if (poSrcDS->GetGCPCount() > 0 && eErr == CE_None)
760
0
    {
761
0
        eErr = poDstDS->SetGCPs(poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(),
762
0
                                poSrcDS->GetGCPProjection());
763
0
        if (!bStrict)
764
0
            eErr = CE_None;
765
0
    }
766
767
0
    if (nDstBands == 0 && !bStrict)
768
0
        CPLTurnFailureIntoWarning(false);
769
770
    /* -------------------------------------------------------------------- */
771
    /*      Copy metadata.                                                  */
772
    /* -------------------------------------------------------------------- */
773
0
    DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
774
775
    /* -------------------------------------------------------------------- */
776
    /*      Loop copying bands.                                             */
777
    /* -------------------------------------------------------------------- */
778
0
    for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
779
0
    {
780
0
        GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
781
0
        GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
782
783
        /* --------------------------------------------------------------------
784
         */
785
        /*      Do we need to copy a colortable. */
786
        /* --------------------------------------------------------------------
787
         */
788
0
        GDALColorTable *const poCT = poSrcBand->GetColorTable();
789
0
        if (poCT != nullptr)
790
0
            poDstBand->SetColorTable(poCT);
791
792
        /* --------------------------------------------------------------------
793
         */
794
        /*      Do we need to copy other metadata?  Most of this is */
795
        /*      non-critical, so lets not bother folks if it fails are we */
796
        /*      are not in strict mode. */
797
        /* --------------------------------------------------------------------
798
         */
799
0
        if (!bStrict)
800
0
            CPLTurnFailureIntoWarning(true);
801
802
0
        if (strlen(poSrcBand->GetDescription()) > 0)
803
0
            poDstBand->SetDescription(poSrcBand->GetDescription());
804
805
0
        if (CSLCount(poSrcBand->GetMetadata()) > 0)
806
0
            poDstBand->SetMetadata(poSrcBand->GetMetadata());
807
808
0
        int bSuccess = FALSE;
809
0
        double dfValue = poSrcBand->GetOffset(&bSuccess);
810
0
        if (bSuccess && dfValue != 0.0)
811
0
            poDstBand->SetOffset(dfValue);
812
813
0
        dfValue = poSrcBand->GetScale(&bSuccess);
814
0
        if (bSuccess && dfValue != 1.0)
815
0
            poDstBand->SetScale(dfValue);
816
817
0
        GDALCopyNoDataValue(poDstBand, poSrcBand);
818
819
0
        if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
820
0
            poSrcBand->GetColorInterpretation() !=
821
0
                poDstBand->GetColorInterpretation())
822
0
            poDstBand->SetColorInterpretation(
823
0
                poSrcBand->GetColorInterpretation());
824
825
0
        char **papszCatNames = poSrcBand->GetCategoryNames();
826
0
        if (nullptr != papszCatNames)
827
0
            poDstBand->SetCategoryNames(papszCatNames);
828
829
        // Only copy RAT if it is of reasonable size to fit in memory
830
0
        GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
831
0
        if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
832
0
                                        poRAT->GetRowCount() <
833
0
                                    1024 * 1024)
834
0
        {
835
0
            poDstBand->SetDefaultRAT(poRAT);
836
0
        }
837
838
0
        if (!bStrict)
839
0
        {
840
0
            CPLTurnFailureIntoWarning(false);
841
0
        }
842
0
        else
843
0
        {
844
0
            eErr = CPLGetLastErrorType();
845
0
        }
846
0
    }
847
848
    /* -------------------------------------------------------------------- */
849
    /*      Copy image data.                                                */
850
    /* -------------------------------------------------------------------- */
851
0
    if (eErr == CE_None && nDstBands > 0)
852
0
    {
853
0
        const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
854
0
                                                              nullptr};
855
0
        const bool bSkipHoles = CPLTestBool(
856
0
            CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
857
0
        eErr = GDALDatasetCopyWholeRaster(
858
0
            poSrcDS, poDstDS,
859
0
            bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
860
0
            pProgressData);
861
0
    }
862
863
    /* -------------------------------------------------------------------- */
864
    /*      Should we copy some masks over?                                 */
865
    /* -------------------------------------------------------------------- */
866
0
    if (eErr == CE_None && nDstBands > 0)
867
0
        eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
868
869
    /* -------------------------------------------------------------------- */
870
    /*      Copy vector layers                                              */
871
    /* -------------------------------------------------------------------- */
872
0
    if (eErr == CE_None)
873
0
    {
874
0
        if (nLayerCount > 0 && poDstDS->TestCapability(ODsCCreateLayer))
875
0
        {
876
0
            for (int iLayer = 0; iLayer < nLayerCount; ++iLayer)
877
0
            {
878
0
                OGRLayer *poLayer = poSrcDS->GetLayer(iLayer);
879
880
0
                if (poLayer == nullptr)
881
0
                    continue;
882
883
0
                poDstDS->CopyLayer(poLayer, poLayer->GetName(), nullptr);
884
0
            }
885
0
        }
886
0
    }
887
888
    /* -------------------------------------------------------------------- */
889
    /*      Try to cleanup the output dataset if the translation failed.    */
890
    /* -------------------------------------------------------------------- */
891
0
    if (eErr != CE_None)
892
0
    {
893
0
        delete poDstDS;
894
0
        if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
895
0
        {
896
            // Only delete if creating a new file
897
0
            Delete(pszFilename);
898
0
        }
899
0
        return nullptr;
900
0
    }
901
0
    else
902
0
    {
903
0
        CPLErrorReset();
904
0
    }
905
906
0
    return poDstDS;
907
0
}
908
909
/************************************************************************/
910
/*                        DefaultCopyMetadata()                         */
911
/************************************************************************/
912
913
void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
914
                                     CSLConstList papszOptions,
915
                                     CSLConstList papszExcludedDomains)
916
0
{
917
0
    const char *pszCopySrcMDD =
918
0
        CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
919
0
    char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
920
0
    if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
921
0
        papszSrcMDD)
922
0
    {
923
0
        if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
924
0
             CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
925
0
            CSLFindString(papszExcludedDomains, "") < 0 &&
926
0
            CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
927
0
        {
928
0
            if (poSrcDS->GetMetadata() != nullptr)
929
0
                poDstDS->SetMetadata(poSrcDS->GetMetadata());
930
0
        }
931
932
        /* -------------------------------------------------------------------- */
933
        /*      Copy transportable special domain metadata.                     */
934
        /*      It would be nice to copy geolocation, but it is pretty fragile. */
935
        /* -------------------------------------------------------------------- */
936
0
        constexpr const char *apszDefaultDomains[] = {
937
0
            "RPC", "xml:XMP", "json:ISIS3", "json:VICAR"};
938
0
        for (const char *pszDomain : apszDefaultDomains)
939
0
        {
940
0
            if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
941
0
                CSLFindString(papszExcludedDomains, pszDomain) < 0)
942
0
            {
943
0
                CSLConstList papszMD = poSrcDS->GetMetadata(pszDomain);
944
0
                if (papszMD)
945
0
                    poDstDS->SetMetadata(papszMD, pszDomain);
946
0
            }
947
0
        }
948
949
0
        if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
950
0
            papszSrcMDD)
951
0
        {
952
0
            for (const char *pszDomain :
953
0
                 CPLStringList(poSrcDS->GetMetadataDomainList()))
954
0
            {
955
0
                if (pszDomain[0] != 0 &&
956
0
                    (!papszSrcMDD ||
957
0
                     CSLFindString(papszSrcMDD, pszDomain) >= 0))
958
0
                {
959
0
                    bool bCanCopy = true;
960
0
                    if (CSLFindString(papszExcludedDomains, pszDomain) >= 0)
961
0
                    {
962
0
                        bCanCopy = false;
963
0
                    }
964
0
                    else
965
0
                    {
966
0
                        for (const char *pszOtherDomain : apszDefaultDomains)
967
0
                        {
968
0
                            if (EQUAL(pszDomain, pszOtherDomain))
969
0
                            {
970
0
                                bCanCopy = false;
971
0
                                break;
972
0
                            }
973
0
                        }
974
0
                        if (!papszSrcMDD)
975
0
                        {
976
0
                            constexpr const char *const apszReservedDomains[] =
977
0
                                {"IMAGE_STRUCTURE", "DERIVED_SUBDATASETS"};
978
0
                            for (const char *pszOtherDomain :
979
0
                                 apszReservedDomains)
980
0
                            {
981
0
                                if (EQUAL(pszDomain, pszOtherDomain))
982
0
                                {
983
0
                                    bCanCopy = false;
984
0
                                    break;
985
0
                                }
986
0
                            }
987
0
                        }
988
0
                    }
989
0
                    if (bCanCopy)
990
0
                    {
991
0
                        poDstDS->SetMetadata(poSrcDS->GetMetadata(pszDomain),
992
0
                                             pszDomain);
993
0
                    }
994
0
                }
995
0
            }
996
0
        }
997
0
    }
998
0
    CSLDestroy(papszSrcMDD);
999
0
}
1000
1001
/************************************************************************/
1002
/*                      QuietDeleteForCreateCopy()                      */
1003
/************************************************************************/
1004
1005
CPLErr GDALDriver::QuietDeleteForCreateCopy(const char *pszFilename,
1006
                                            GDALDataset *poSrcDS)
1007
0
{
1008
    // Someone issuing CreateCopy("foo.tif") on a
1009
    // memory driver doesn't expect files with those names to be deleted
1010
    // on a file system...
1011
    // This is somewhat messy. Ideally there should be a way for the
1012
    // driver to overload the default behavior
1013
0
    if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
1014
        // Also exclude database formats for which there's no file list
1015
        // and whose opening might be slow (GeoRaster in particular)
1016
0
        !EQUAL(GetDescription(), "GeoRaster") &&
1017
0
        !EQUAL(GetDescription(), "PostGISRaster"))
1018
0
    {
1019
        /* --------------------------------------------------------------------
1020
         */
1021
        /*      Establish list of files of output dataset if it already
1022
         * exists. */
1023
        /* --------------------------------------------------------------------
1024
         */
1025
0
        std::set<std::string> oSetExistingDestFiles;
1026
0
        {
1027
0
            CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1028
0
            const char *const apszAllowedDrivers[] = {GetDescription(),
1029
0
                                                      nullptr};
1030
0
            auto poExistingOutputDS =
1031
0
                std::unique_ptr<GDALDataset>(GDALDataset::Open(
1032
0
                    pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1033
0
            if (poExistingOutputDS)
1034
0
            {
1035
0
                for (const char *pszFileInList :
1036
0
                     CPLStringList(poExistingOutputDS->GetFileList()))
1037
0
                {
1038
0
                    oSetExistingDestFiles.insert(
1039
0
                        CPLString(pszFileInList).replaceAll('\\', '/'));
1040
0
                }
1041
0
            }
1042
0
        }
1043
1044
        /* --------------------------------------------------------------------
1045
         */
1046
        /*      Check if the source dataset shares some files with the dest
1047
         * one.*/
1048
        /* --------------------------------------------------------------------
1049
         */
1050
0
        std::set<std::string> oSetExistingDestFilesFoundInSource;
1051
0
        if (!oSetExistingDestFiles.empty())
1052
0
        {
1053
0
            CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1054
            // We need to reopen in a temporary dataset for the particular
1055
            // case of overwritten a .tif.ovr file from a .tif
1056
            // If we probe the file list of the .tif, it will then open the
1057
            // .tif.ovr !
1058
0
            const char *const apszAllowedDrivers[] = {
1059
0
                poSrcDS->GetDriver() ? poSrcDS->GetDriver()->GetDescription()
1060
0
                                     : nullptr,
1061
0
                nullptr};
1062
0
            auto poSrcDSTmp = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1063
0
                poSrcDS->GetDescription(), GDAL_OF_RASTER, apszAllowedDrivers,
1064
0
                poSrcDS->papszOpenOptions));
1065
0
            if (poSrcDSTmp)
1066
0
            {
1067
0
                for (const char *pszFileInList :
1068
0
                     CPLStringList(poSrcDSTmp->GetFileList()))
1069
0
                {
1070
0
                    CPLString osFilename(pszFileInList);
1071
0
                    osFilename.replaceAll('\\', '/');
1072
0
                    if (cpl::contains(oSetExistingDestFiles, osFilename))
1073
0
                    {
1074
0
                        oSetExistingDestFilesFoundInSource.insert(
1075
0
                            std::move(osFilename));
1076
0
                    }
1077
0
                }
1078
0
            }
1079
0
        }
1080
1081
        // If the source file(s) and the dest one share some files in
1082
        // common, only remove the files that are *not* in common
1083
0
        if (!oSetExistingDestFilesFoundInSource.empty())
1084
0
        {
1085
0
            for (const std::string &osFilename : oSetExistingDestFiles)
1086
0
            {
1087
0
                if (!cpl::contains(oSetExistingDestFilesFoundInSource,
1088
0
                                   osFilename))
1089
0
                {
1090
0
                    VSIUnlink(osFilename.c_str());
1091
0
                }
1092
0
            }
1093
0
        }
1094
1095
0
        QuietDelete(pszFilename);
1096
0
    }
1097
1098
0
    return CE_None;
1099
0
}
1100
1101
//! @endcond
1102
1103
/************************************************************************/
1104
/*                             CreateCopy()                             */
1105
/************************************************************************/
1106
1107
/**
1108
 * \brief Create a copy of a dataset.
1109
 *
1110
 * This method will attempt to create a copy of a raster dataset with the
1111
 * indicated filename, and in this drivers format.  Band number, size,
1112
 * type, projection, geotransform and so forth are all to be copied from
1113
 * the provided template dataset.
1114
 *
1115
 * Note that many sequential write once formats (such as JPEG and PNG) don't
1116
 * implement the Create() method but do implement this CreateCopy() method.
1117
 * If the driver doesn't implement CreateCopy(), but does implement Create()
1118
 * then the default CreateCopy() mechanism built on calling Create() will
1119
 * be used.
1120
 * So to test if CreateCopy() is available, you can test if GDAL_DCAP_CREATECOPY
1121
 * or GDAL_DCAP_CREATE is set in the GDAL metadata.
1122
 *
1123
 * It is intended that CreateCopy() will often be used with a source dataset
1124
 * which is a virtual dataset allowing configuration of band types, and other
1125
 * information without actually duplicating raster data (see the VRT driver).
1126
 * This is what is done by the gdal_translate utility for example.
1127
 *
1128
 * That function will try to validate the creation option list passed to the
1129
 * driver with the GDALValidateCreationOptions() method. This check can be
1130
 * disabled by defining the configuration option
1131
 * GDAL_VALIDATE_CREATION_OPTIONS=NO.
1132
 *
1133
 * This function copy all metadata from the default domain ("")
1134
 *
1135
 * Even is bStrict is TRUE, only the <b>value</b> of the data is equivalent,
1136
 * but the data layout (INTERLEAVE as PIXEL/LINE/BAND) of the dst dataset is
1137
 * controlled by the papszOptions creation options, and may differ from the
1138
 * poSrcDS src dataset.
1139
 * Starting from GDAL 3.5, if no INTERLEAVE and COMPRESS creation option has
1140
 * been specified in papszOptions, and if the driver supports equivalent
1141
 * interleaving as the src dataset, the CreateCopy() will internally add the
1142
 * proper creation option to get the same data interleaving.
1143
 *
1144
 * After you have finished working with the returned dataset, it is
1145
 * <b>required</b> to close it with GDALClose(). This does not only close the
1146
 * file handle, but also ensures that all the data and metadata has been written
1147
 * to the dataset (GDALFlushCache() is not sufficient for that purpose).
1148
 *
1149
 * For multidimensional datasets, papszOptions can contain array creation
1150
 * options, if they are prefixed with "ARRAY:". \see GDALGroup::CopyFrom()
1151
 * documentation for further details regarding such options.
1152
 *
1153
 * @param pszFilename the name for the new dataset.  UTF-8 encoded.
1154
 * @param poSrcDS the dataset being duplicated.
1155
 * @param bStrict TRUE if the copy must be strictly equivalent, or more
1156
 * normally FALSE indicating that the copy may adapt as needed for the
1157
 * output format.
1158
 * @param papszOptions additional format dependent options controlling
1159
 * creation of the output file.
1160
 * The APPEND_SUBDATASET=YES option can be specified to avoid prior destruction
1161
 * of existing dataset.
1162
 * Starting with GDAL 3.8.0, the following options are recognized by the
1163
 * GTiff, COG, VRT, PNG au JPEG drivers:
1164
 * <ul>
1165
 * <li>COPY_SRC_MDD=AUTO/YES/NO: whether metadata domains of the source dataset
1166
 * should be copied to the destination dataset. In the default AUTO mode, only
1167
 * "safe" domains will be copied, which include the default metadata domain
1168
 * (some drivers may include other domains such as IMD, RPC, GEOLOCATION). When
1169
 * setting YES, all domains will be copied (but a few reserved ones like
1170
 * IMAGE_STRUCTURE or DERIVED_SUBDATASETS). When setting NO, no source metadata
1171
 * will be copied.
1172
 * </li>
1173
 *<li>SRC_MDD=domain_name: which source metadata domain should be copied.
1174
 * This option restricts the list of source metadata domains to be copied
1175
 * (it implies COPY_SRC_MDD=YES if it is not set). This option may be specified
1176
 * as many times as they are source domains. The default metadata domain is the
1177
 * empty string "" ("_DEFAULT_") may also be used when empty string is not practical)
1178
 * </li>
1179
 * </ul>
1180
 * @param pfnProgress a function to be used to report progress of the copy.
1181
 * @param pProgressData application data passed into progress function.
1182
 *
1183
 * @return a pointer to the newly created dataset (may be read-only access).
1184
 */
1185
1186
GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1187
                                    GDALDataset *poSrcDS, int bStrict,
1188
                                    CSLConstList papszOptions,
1189
                                    GDALProgressFunc pfnProgress,
1190
                                    void *pProgressData)
1191
1192
0
{
1193
0
    if (pfnProgress == nullptr)
1194
0
        pfnProgress = GDALDummyProgress;
1195
1196
0
    const int nBandCount = poSrcDS->GetRasterCount();
1197
1198
    /* -------------------------------------------------------------------- */
1199
    /*      If no INTERLEAVE creation option is given, we will try to add   */
1200
    /*      one that matches the current srcDS interleaving                 */
1201
    /* -------------------------------------------------------------------- */
1202
0
    char **papszOptionsToDelete = nullptr;
1203
0
    const char *srcInterleave =
1204
0
        poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
1205
0
    if (nBandCount > 1 && srcInterleave != nullptr &&
1206
0
        CSLFetchNameValue(papszOptions, "INTERLEAVE") == nullptr &&
1207
0
        EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
1208
0
    {
1209
1210
        // look for INTERLEAVE values of the driver
1211
0
        char **interleavesCSL = nullptr;
1212
0
        const char *pszOptionList =
1213
0
            this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1214
0
        CPLXMLNode *xmlNode =
1215
0
            !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
1216
0
        for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
1217
0
             child != nullptr; child = child->psNext)
1218
0
        {
1219
0
            if ((child->eType == CXT_Element) &&
1220
0
                EQUAL(child->pszValue, "Option"))
1221
0
            {
1222
0
                const char *nameAttribute =
1223
0
                    CPLGetXMLValue(child, "name", nullptr);
1224
0
                const bool isInterleaveAttribute =
1225
0
                    nameAttribute && EQUAL(nameAttribute, "INTERLEAVE");
1226
0
                if (isInterleaveAttribute)
1227
0
                {
1228
0
                    for (CPLXMLNode *optionChild = child->psChild;
1229
0
                         optionChild != nullptr;
1230
0
                         optionChild = optionChild->psNext)
1231
0
                    {
1232
0
                        if ((optionChild->eType == CXT_Element) &&
1233
0
                            EQUAL(optionChild->pszValue, "Value"))
1234
0
                        {
1235
0
                            CPLXMLNode *optionChildValue = optionChild->psChild;
1236
0
                            if (optionChildValue &&
1237
0
                                (optionChildValue->eType == CXT_Text))
1238
0
                            {
1239
0
                                interleavesCSL = CSLAddString(
1240
0
                                    interleavesCSL, optionChildValue->pszValue);
1241
0
                            }
1242
0
                        }
1243
0
                    }
1244
0
                }
1245
0
            }
1246
0
        }
1247
0
        CPLDestroyXMLNode(xmlNode);
1248
1249
0
        const char *dstInterleaveBand =
1250
0
            (CSLFindString(interleavesCSL, "BAND") >= 0)  ? "BAND"
1251
0
            : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
1252
0
                                                          : nullptr;
1253
0
        const char *dstInterleaveLine =
1254
0
            (CSLFindString(interleavesCSL, "LINE") >= 0)  ? "LINE"
1255
0
            : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
1256
0
                                                          : nullptr;
1257
0
        const char *dstInterleavePixel =
1258
0
            (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
1259
0
            : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
1260
0
                                                          : nullptr;
1261
0
        const char *dstInterleave =
1262
0
            EQUAL(srcInterleave, "BAND")    ? dstInterleaveBand
1263
0
            : EQUAL(srcInterleave, "LINE")  ? dstInterleaveLine
1264
0
            : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
1265
0
                                            : nullptr;
1266
0
        CSLDestroy(interleavesCSL);
1267
1268
0
        if (dstInterleave != nullptr)
1269
0
        {
1270
0
            papszOptionsToDelete = CSLDuplicate(papszOptions);
1271
0
            papszOptionsToDelete = CSLSetNameValue(papszOptionsToDelete,
1272
0
                                                   "INTERLEAVE", dstInterleave);
1273
0
            papszOptionsToDelete = CSLSetNameValue(
1274
0
                papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1275
0
            papszOptions = papszOptionsToDelete;
1276
0
        }
1277
0
    }
1278
1279
    /* -------------------------------------------------------------------- */
1280
    /*      Make sure we cleanup if there is an existing dataset of this    */
1281
    /*      name.  But even if that seems to fail we will continue since    */
1282
    /*      it might just be a corrupt file or something.                   */
1283
    /* -------------------------------------------------------------------- */
1284
0
    const bool bAppendSubdataset =
1285
0
        CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false);
1286
    // Note: @QUIET_DELETE_ON_CREATE_COPY is set to NO by the KMLSuperOverlay
1287
    // driver when writing a .kmz file. Also by GDALTranslate() if it has
1288
    // already done a similar job.
1289
0
    if (!bAppendSubdataset &&
1290
0
        CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1291
0
    {
1292
0
        QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1293
0
    }
1294
1295
0
    int iIdxQuietDeleteOnCreateCopy =
1296
0
        CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1297
0
    if (iIdxQuietDeleteOnCreateCopy >= 0)
1298
0
    {
1299
0
        if (papszOptionsToDelete == nullptr)
1300
0
            papszOptionsToDelete = CSLDuplicate(papszOptions);
1301
0
        papszOptionsToDelete = CSLRemoveStrings(
1302
0
            papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1303
0
        papszOptions = papszOptionsToDelete;
1304
0
    }
1305
1306
    /* -------------------------------------------------------------------- */
1307
    /*      If _INTERNAL_DATASET=YES, the returned dataset will not be      */
1308
    /*      registered in the global list of open datasets.                 */
1309
    /* -------------------------------------------------------------------- */
1310
0
    const int iIdxInternalDataset =
1311
0
        CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1312
0
    bool bInternalDataset = false;
1313
0
    if (iIdxInternalDataset >= 0)
1314
0
    {
1315
0
        bInternalDataset =
1316
0
            CPLFetchBool(papszOptions, "_INTERNAL_DATASET", false);
1317
0
        if (papszOptionsToDelete == nullptr)
1318
0
            papszOptionsToDelete = CSLDuplicate(papszOptions);
1319
0
        papszOptionsToDelete = CSLRemoveStrings(
1320
0
            papszOptionsToDelete, iIdxInternalDataset, 1, nullptr);
1321
0
        papszOptions = papszOptionsToDelete;
1322
0
    }
1323
1324
    /* -------------------------------------------------------------------- */
1325
    /*      Validate creation options.                                      */
1326
    /* -------------------------------------------------------------------- */
1327
0
    if (CPLTestBool(
1328
0
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1329
0
    {
1330
0
        auto poSrcGroup = poSrcDS->GetRootGroup();
1331
0
        if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
1332
0
        {
1333
0
            CPLStringList aosDatasetCO;
1334
0
            for (const char *pszOption : cpl::Iterate(papszOptions))
1335
0
            {
1336
0
                if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
1337
0
                    aosDatasetCO.AddString(pszOption);
1338
0
            }
1339
0
            GDALValidateCreationOptions(this, aosDatasetCO.List());
1340
0
        }
1341
0
        else
1342
0
        {
1343
0
            GDALValidateCreationOptions(this, papszOptions);
1344
0
        }
1345
0
    }
1346
1347
    /* -------------------------------------------------------------------- */
1348
    /*      Advise the source raster that we are going to read it completely */
1349
    /* -------------------------------------------------------------------- */
1350
1351
0
    const int nXSize = poSrcDS->GetRasterXSize();
1352
0
    const int nYSize = poSrcDS->GetRasterYSize();
1353
0
    GDALDataType eDT = GDT_Unknown;
1354
0
    if (nBandCount > 0)
1355
0
    {
1356
0
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1357
0
        if (poSrcBand)
1358
0
            eDT = poSrcBand->GetRasterDataType();
1359
0
    }
1360
0
    poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1361
0
                        nullptr, nullptr);
1362
1363
    /* -------------------------------------------------------------------- */
1364
    /*      If the format provides a CreateCopy() method use that,          */
1365
    /*      otherwise fallback to the internal implementation using the     */
1366
    /*      Create() method.                                                */
1367
    /* -------------------------------------------------------------------- */
1368
0
    GDALDataset *poDstDS = nullptr;
1369
0
    auto l_pfnCreateCopy = GetCreateCopyCallback();
1370
0
    if (l_pfnCreateCopy != nullptr &&
1371
0
        !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1372
0
    {
1373
0
        poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1374
0
                                  const_cast<char **>(papszOptions),
1375
0
                                  pfnProgress, pProgressData);
1376
0
        if (poDstDS != nullptr)
1377
0
        {
1378
0
            if (poDstDS->GetDescription() == nullptr ||
1379
0
                strlen(poDstDS->GetDescription()) == 0)
1380
0
                poDstDS->SetDescription(pszFilename);
1381
1382
0
            if (poDstDS->poDriver == nullptr)
1383
0
                poDstDS->poDriver = this;
1384
1385
0
            if (!bInternalDataset)
1386
0
                poDstDS->AddToDatasetOpenList();
1387
0
        }
1388
0
    }
1389
0
    else
1390
0
    {
1391
0
        poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1392
0
                                    pfnProgress, pProgressData);
1393
0
    }
1394
1395
0
    CSLDestroy(papszOptionsToDelete);
1396
0
    return poDstDS;
1397
0
}
1398
1399
/************************************************************************/
1400
/*                           GDALCreateCopy()                           */
1401
/************************************************************************/
1402
1403
/**
1404
 * \brief Create a copy of a dataset.
1405
 *
1406
 * @see GDALDriver::CreateCopy()
1407
 */
1408
1409
GDALDatasetH CPL_STDCALL GDALCreateCopy(GDALDriverH hDriver,
1410
                                        const char *pszFilename,
1411
                                        GDALDatasetH hSrcDS, int bStrict,
1412
                                        CSLConstList papszOptions,
1413
                                        GDALProgressFunc pfnProgress,
1414
                                        void *pProgressData)
1415
1416
0
{
1417
0
    VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1418
0
    VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1419
1420
0
    return GDALDriver::FromHandle(hDriver)->CreateCopy(
1421
0
        pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1422
0
        pfnProgress, pProgressData);
1423
0
}
1424
1425
/************************************************************************/
1426
/*                       CanVectorTranslateFrom()                       */
1427
/************************************************************************/
1428
1429
/** Returns whether the driver can translate from a vector dataset,
1430
 * using the arguments passed to GDALVectorTranslate() stored in
1431
 * papszVectorTranslateArguments.
1432
 *
1433
 * This is used to determine if the driver supports the VectorTranslateFrom()
1434
 * operation.
1435
 *
1436
 * @param pszDestName Target dataset name
1437
 * @param poSourceDS  Source dataset
1438
 * @param papszVectorTranslateArguments Non-positional arguments passed to
1439
 *                                      GDALVectorTranslate() (may be nullptr)
1440
 * @param[out] ppapszFailureReasons nullptr, or a pointer to an null-terminated
1441
 * array of strings to record the reason(s) for the impossibility.
1442
 * @return true if VectorTranslateFrom() can be called with the same arguments.
1443
 * @since GDAL 3.8
1444
 */
1445
bool GDALDriver::CanVectorTranslateFrom(
1446
    const char *pszDestName, GDALDataset *poSourceDS,
1447
    CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1448
1449
0
{
1450
0
    if (ppapszFailureReasons)
1451
0
    {
1452
0
        *ppapszFailureReasons = nullptr;
1453
0
    }
1454
1455
0
    if (!pfnCanVectorTranslateFrom)
1456
0
    {
1457
0
        if (ppapszFailureReasons)
1458
0
        {
1459
0
            *ppapszFailureReasons = CSLAddString(
1460
0
                nullptr,
1461
0
                "CanVectorTranslateFrom() not implemented for this driver");
1462
0
        }
1463
0
        return false;
1464
0
    }
1465
1466
0
    char **papszFailureReasons = nullptr;
1467
0
    bool bRet = pfnCanVectorTranslateFrom(
1468
0
        pszDestName, poSourceDS, papszVectorTranslateArguments,
1469
0
        ppapszFailureReasons ? ppapszFailureReasons : &papszFailureReasons);
1470
0
    if (!ppapszFailureReasons)
1471
0
    {
1472
0
        for (const char *pszReason :
1473
0
             cpl::Iterate(static_cast<CSLConstList>(papszFailureReasons)))
1474
0
        {
1475
0
            CPLDebug("GDAL", "%s", pszReason);
1476
0
        }
1477
0
        CSLDestroy(papszFailureReasons);
1478
0
    }
1479
0
    return bRet;
1480
0
}
1481
1482
bool GDALDriver::HasOpenOption(const char *pszOpenOptionName) const
1483
0
{
1484
0
    if (pszOpenOptionName == nullptr)
1485
0
        return false;
1486
1487
    // Const cast is safe here since we are only reading the metadata
1488
0
    auto pszOOMd{const_cast<GDALDriver *>(this)->GetMetadataItem(
1489
0
        GDAL_DMD_OPENOPTIONLIST)};
1490
0
    if (pszOOMd == nullptr)
1491
0
        return false;
1492
1493
0
    const CPLXMLTreeCloser oXml{CPLParseXMLString(pszOOMd)};
1494
0
    for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1495
0
         option = option->psNext)
1496
0
    {
1497
0
        if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1498
0
                  pszOpenOptionName))
1499
0
            return true;
1500
0
    }
1501
0
    return false;
1502
0
}
1503
1504
/************************************************************************/
1505
/*                        VectorTranslateFrom()                         */
1506
/************************************************************************/
1507
1508
/** Create a copy of a vector dataset, using the arguments passed to
1509
 * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1510
 *
1511
 * This may be implemented by some drivers that can convert from an existing
1512
 * dataset in an optimized way.
1513
 *
1514
 * This is for example used by the PMTiles to convert from MBTiles.
1515
 *
1516
 * @param pszDestName Target dataset name
1517
 * @param poSourceDS  Source dataset
1518
 * @param papszVectorTranslateArguments Non-positional arguments passed to
1519
 *                                      GDALVectorTranslate() (may be nullptr)
1520
 * @param pfnProgress a function to be used to report progress of the copy.
1521
 * @param pProgressData application data passed into progress function.
1522
 * @return a new dataset in case of success, or nullptr in case of error.
1523
 * @since GDAL 3.8
1524
 */
1525
GDALDataset *GDALDriver::VectorTranslateFrom(
1526
    const char *pszDestName, GDALDataset *poSourceDS,
1527
    CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1528
    void *pProgressData)
1529
1530
0
{
1531
0
    if (!pfnVectorTranslateFrom)
1532
0
    {
1533
0
        CPLError(CE_Failure, CPLE_AppDefined,
1534
0
                 "VectorTranslateFrom() not implemented for this driver");
1535
0
        return nullptr;
1536
0
    }
1537
1538
0
    return pfnVectorTranslateFrom(pszDestName, poSourceDS,
1539
0
                                  papszVectorTranslateArguments, pfnProgress,
1540
0
                                  pProgressData);
1541
0
}
1542
1543
/************************************************************************/
1544
/*                            QuietDelete()                             */
1545
/************************************************************************/
1546
1547
/**
1548
 * \brief Delete dataset if found.
1549
 *
1550
 * This is a helper method primarily used by Create() and
1551
 * CreateCopy() to predelete any dataset of the name soon to be
1552
 * created.  It will attempt to delete the named dataset if
1553
 * one is found, otherwise it does nothing.  An error is only
1554
 * returned if the dataset is found but the delete fails.
1555
 *
1556
 * This is a static method and it doesn't matter what driver instance
1557
 * it is invoked on.  It will attempt to discover the correct driver
1558
 * using Identify().
1559
 *
1560
 * @param pszName the dataset name to try and delete.
1561
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1562
 * terminated list of strings with the driver short names that must be
1563
 * considered. (Note: implemented only starting with GDAL 3.4.1)
1564
 * @return CE_None if the dataset does not exist, or is deleted without issues.
1565
 */
1566
1567
CPLErr GDALDriver::QuietDelete(const char *pszName,
1568
                               CSLConstList papszAllowedDrivers)
1569
1570
0
{
1571
0
    VSIStatBufL sStat;
1572
0
    const bool bExists =
1573
0
        VSIStatExL(pszName, &sStat,
1574
0
                   VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1575
1576
0
#ifdef S_ISFIFO
1577
0
    if (bExists && S_ISFIFO(sStat.st_mode))
1578
0
        return CE_None;
1579
0
#endif
1580
1581
0
    GDALDriver *poDriver = nullptr;
1582
0
    if (papszAllowedDrivers)
1583
0
    {
1584
0
        GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
1585
0
        for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
1586
0
        {
1587
0
            GDALDriver *poTmpDriver =
1588
0
                GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
1589
0
            if (poTmpDriver)
1590
0
            {
1591
0
                const bool bIdentifyRes =
1592
0
                    poTmpDriver->pfnIdentifyEx
1593
0
                        ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
1594
0
                              0
1595
0
                        : poTmpDriver->pfnIdentify &&
1596
0
                              poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
1597
0
                if (bIdentifyRes)
1598
0
                {
1599
0
                    poDriver = poTmpDriver;
1600
0
                    break;
1601
0
                }
1602
0
            }
1603
0
        }
1604
0
    }
1605
0
    else
1606
0
    {
1607
0
        CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1608
0
        poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1609
0
    }
1610
1611
0
    if (poDriver == nullptr)
1612
0
        return CE_None;
1613
1614
0
    if (bExists && VSI_ISDIR(sStat.st_mode) &&
1615
0
        (EQUAL(poDriver->GetDescription(), "MapInfo File") ||
1616
0
         EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
1617
0
    {
1618
        // Those drivers are a bit special and handle directories as container
1619
        // of layers, but it is quite common to found other files too, and
1620
        // removing the directory might be non-desirable.
1621
0
        return CE_None;
1622
0
    }
1623
1624
0
    CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
1625
1626
0
    poDriver->pfnDelete = poDriver->GetDeleteCallback();
1627
0
    const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
1628
0
                        poDriver->pfnDeleteDataSource == nullptr;
1629
0
    if (bQuiet)
1630
0
    {
1631
0
        CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1632
0
        return poDriver->Delete(pszName);
1633
0
    }
1634
0
    else
1635
0
    {
1636
0
        return poDriver->Delete(pszName);
1637
0
    }
1638
0
}
1639
1640
/************************************************************************/
1641
/*                               Delete()                               */
1642
/************************************************************************/
1643
1644
/**
1645
 * \brief Delete named dataset.
1646
 *
1647
 * The driver will attempt to delete the named dataset in a driver specific
1648
 * fashion.  Full featured drivers will delete all associated files,
1649
 * database objects, or whatever is appropriate.  The default behavior when
1650
 * no driver specific behavior is provided is to attempt to delete all the
1651
 * files that are returned by GDALGetFileList() on the dataset handle.
1652
 *
1653
 * It is unwise to have open dataset handles on this dataset when it is
1654
 * deleted.
1655
 *
1656
 * Equivalent of the C function GDALDeleteDataset().
1657
 *
1658
 * @param pszFilename name of dataset to delete.
1659
 *
1660
 * @return CE_None on success, or CE_Failure if the operation fails.
1661
 */
1662
1663
CPLErr GDALDriver::Delete(const char *pszFilename)
1664
1665
0
{
1666
0
    pfnDelete = GetDeleteCallback();
1667
0
    if (pfnDelete != nullptr)
1668
0
        return pfnDelete(pszFilename);
1669
0
    else if (pfnDeleteDataSource != nullptr)
1670
0
        return pfnDeleteDataSource(this, pszFilename);
1671
1672
    /* -------------------------------------------------------------------- */
1673
    /*      Collect file list.                                              */
1674
    /* -------------------------------------------------------------------- */
1675
0
    GDALDatasetH hDS = GDALOpenEx(pszFilename, GDAL_OF_VERBOSE_ERROR, nullptr,
1676
0
                                  nullptr, nullptr);
1677
1678
0
    if (hDS == nullptr)
1679
0
    {
1680
0
        if (CPLGetLastErrorNo() == 0)
1681
0
            CPLError(CE_Failure, CPLE_OpenFailed,
1682
0
                     "Unable to open %s to obtain file list.", pszFilename);
1683
1684
0
        return CE_Failure;
1685
0
    }
1686
1687
0
    const CPLStringList aosFileList(GDALGetFileList(hDS));
1688
1689
0
    GDALClose(hDS);
1690
0
    hDS = nullptr;
1691
1692
0
    if (aosFileList.empty())
1693
0
    {
1694
0
        CPLError(CE_Failure, CPLE_NotSupported,
1695
0
                 "Unable to determine files associated with %s, "
1696
0
                 "delete fails.",
1697
0
                 pszFilename);
1698
0
        return CE_Failure;
1699
0
    }
1700
1701
0
    return Delete(nullptr, aosFileList.List());
1702
0
}
1703
1704
/************************************************************************/
1705
/*                               Delete()                               */
1706
/************************************************************************/
1707
1708
/**
1709
 * \brief Delete a currently opened dataset
1710
 *
1711
 * The driver will attempt to delete the passed dataset in a driver specific
1712
 * fashion.  Full featured drivers will delete all associated files,
1713
 * database objects, or whatever is appropriate.  The default behavior when
1714
 * no driver specific behavior is provided is to attempt to delete all the
1715
 * files that are returned by GDALGetFileList() on the dataset handle.
1716
 *
1717
 * Note that this will generally not work on Windows systems that don't accept
1718
 * deleting opened files.
1719
 *
1720
 * At least one of poDS or papszFileList must not be NULL
1721
 *
1722
 * @param poDS dataset to delete, or NULL
1723
 * @param papszFileList File list to delete, typically obtained with
1724
 *                      poDS->GetFileList(), or NULL
1725
 *
1726
 * @return CE_None on success, or CE_Failure if the operation fails.
1727
 *
1728
 * @since 3.12
1729
 */
1730
1731
CPLErr GDALDriver::Delete(GDALDataset *poDS, CSLConstList papszFileList)
1732
1733
0
{
1734
0
    if (poDS)
1735
0
    {
1736
0
        pfnDelete = GetDeleteCallback();
1737
0
        if (pfnDelete != nullptr)
1738
0
            return pfnDelete(poDS->GetDescription());
1739
0
        else if (pfnDeleteDataSource != nullptr)
1740
0
            return pfnDeleteDataSource(this, poDS->GetDescription());
1741
0
    }
1742
1743
    /* -------------------------------------------------------------------- */
1744
    /*      Delete all files.                                               */
1745
    /* -------------------------------------------------------------------- */
1746
0
    CPLErr eErr = CE_None;
1747
0
    for (int i = 0; papszFileList && papszFileList[i]; ++i)
1748
0
    {
1749
0
        if (VSIUnlink(papszFileList[i]) != 0)
1750
0
        {
1751
0
            CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1752
0
                     papszFileList[i], VSIStrerror(errno));
1753
0
            eErr = CE_Failure;
1754
0
        }
1755
0
    }
1756
1757
0
    return eErr;
1758
0
}
1759
1760
/************************************************************************/
1761
/*                         GDALDeleteDataset()                          */
1762
/************************************************************************/
1763
1764
/**
1765
 * \brief Delete named dataset.
1766
 *
1767
 * @see GDALDriver::Delete()
1768
 */
1769
1770
CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
1771
                                     const char *pszFilename)
1772
1773
0
{
1774
0
    if (hDriver == nullptr)
1775
0
        hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1776
1777
0
    if (hDriver == nullptr)
1778
0
    {
1779
0
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1780
0
                 pszFilename);
1781
0
        return CE_Failure;
1782
0
    }
1783
1784
0
#ifdef OGRAPISPY_ENABLED
1785
0
    if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
1786
0
    {
1787
0
        OGRAPISpyDeleteDataSource(hDriver, pszFilename);
1788
0
    }
1789
0
#endif
1790
1791
0
    return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
1792
0
}
1793
1794
/************************************************************************/
1795
/*                           DefaultRename()                            */
1796
/*                                                                      */
1797
/*      The generic implementation based on the file list used when     */
1798
/*      there is no format specific implementation.                     */
1799
/************************************************************************/
1800
1801
//! @cond Doxygen_Suppress
1802
CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
1803
1804
0
{
1805
    /* -------------------------------------------------------------------- */
1806
    /*      Collect file list.                                              */
1807
    /* -------------------------------------------------------------------- */
1808
0
    GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1809
1810
0
    if (hDS == nullptr)
1811
0
    {
1812
0
        if (CPLGetLastErrorNo() == 0)
1813
0
            CPLError(CE_Failure, CPLE_OpenFailed,
1814
0
                     "Unable to open %s to obtain file list.", pszOldName);
1815
1816
0
        return CE_Failure;
1817
0
    }
1818
1819
0
    char **papszFileList = GDALGetFileList(hDS);
1820
1821
0
    GDALClose(hDS);
1822
1823
0
    if (CSLCount(papszFileList) == 0)
1824
0
    {
1825
0
        CPLError(CE_Failure, CPLE_NotSupported,
1826
0
                 "Unable to determine files associated with %s,\n"
1827
0
                 "rename fails.",
1828
0
                 pszOldName);
1829
1830
0
        return CE_Failure;
1831
0
    }
1832
1833
    /* -------------------------------------------------------------------- */
1834
    /*      Produce a list of new filenames that correspond to the old      */
1835
    /*      names.                                                          */
1836
    /* -------------------------------------------------------------------- */
1837
0
    CPLErr eErr = CE_None;
1838
0
    char **papszNewFileList =
1839
0
        CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1840
1841
0
    if (papszNewFileList == nullptr)
1842
0
        return CE_Failure;
1843
1844
0
    for (int i = 0; papszFileList[i] != nullptr; ++i)
1845
0
    {
1846
0
        if (CPLMoveFile(papszNewFileList[i], papszFileList[i]) != 0)
1847
0
        {
1848
0
            eErr = CE_Failure;
1849
            // Try to put the ones we moved back.
1850
0
            for (--i; i >= 0; i--)
1851
0
            {
1852
                // Nothing we can do if the moving back doesn't work...
1853
0
                CPL_IGNORE_RET_VAL(
1854
0
                    CPLMoveFile(papszFileList[i], papszNewFileList[i]));
1855
0
            }
1856
0
            break;
1857
0
        }
1858
0
    }
1859
1860
0
    CSLDestroy(papszNewFileList);
1861
0
    CSLDestroy(papszFileList);
1862
1863
0
    return eErr;
1864
0
}
1865
1866
//! @endcond
1867
1868
/************************************************************************/
1869
/*                               Rename()                               */
1870
/************************************************************************/
1871
1872
/**
1873
 * \brief Rename a dataset.
1874
 *
1875
 * Rename a dataset. This may including moving the dataset to a new directory
1876
 * or even a new filesystem.
1877
 *
1878
 * It is unwise to have open dataset handles on this dataset when it is
1879
 * being renamed.
1880
 *
1881
 * Equivalent of the C function GDALRenameDataset().
1882
 *
1883
 * @param pszNewName new name for the dataset.
1884
 * @param pszOldName old name for the dataset.
1885
 *
1886
 * @return CE_None on success, or CE_Failure if the operation fails.
1887
 */
1888
1889
CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
1890
1891
0
{
1892
0
    pfnRename = GetRenameCallback();
1893
0
    if (pfnRename != nullptr)
1894
0
        return pfnRename(pszNewName, pszOldName);
1895
1896
0
    return DefaultRename(pszNewName, pszOldName);
1897
0
}
1898
1899
/************************************************************************/
1900
/*                         GDALRenameDataset()                          */
1901
/************************************************************************/
1902
1903
/**
1904
 * \brief Rename a dataset.
1905
 *
1906
 * @see GDALDriver::Rename()
1907
 */
1908
1909
CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
1910
                                     const char *pszNewName,
1911
                                     const char *pszOldName)
1912
1913
0
{
1914
0
    if (hDriver == nullptr)
1915
0
        hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1916
1917
0
    if (hDriver == nullptr)
1918
0
    {
1919
0
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1920
0
                 pszOldName);
1921
0
        return CE_Failure;
1922
0
    }
1923
1924
0
    return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
1925
0
}
1926
1927
/************************************************************************/
1928
/*                          DefaultCopyFiles()                          */
1929
/*                                                                      */
1930
/*      The default implementation based on file lists used when        */
1931
/*      there is no format specific implementation.                     */
1932
/************************************************************************/
1933
1934
//! @cond Doxygen_Suppress
1935
CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
1936
                                    const char *pszOldName)
1937
1938
0
{
1939
    /* -------------------------------------------------------------------- */
1940
    /*      Collect file list.                                              */
1941
    /* -------------------------------------------------------------------- */
1942
0
    GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1943
1944
0
    if (hDS == nullptr)
1945
0
    {
1946
0
        if (CPLGetLastErrorNo() == 0)
1947
0
            CPLError(CE_Failure, CPLE_OpenFailed,
1948
0
                     "Unable to open %s to obtain file list.", pszOldName);
1949
1950
0
        return CE_Failure;
1951
0
    }
1952
1953
0
    char **papszFileList = GDALGetFileList(hDS);
1954
1955
0
    GDALClose(hDS);
1956
0
    hDS = nullptr;
1957
1958
0
    if (CSLCount(papszFileList) == 0)
1959
0
    {
1960
0
        CPLError(CE_Failure, CPLE_NotSupported,
1961
0
                 "Unable to determine files associated with %s,\n"
1962
0
                 "rename fails.",
1963
0
                 pszOldName);
1964
1965
0
        return CE_Failure;
1966
0
    }
1967
1968
    /* -------------------------------------------------------------------- */
1969
    /*      Produce a list of new filenames that correspond to the old      */
1970
    /*      names.                                                          */
1971
    /* -------------------------------------------------------------------- */
1972
0
    CPLErr eErr = CE_None;
1973
0
    char **papszNewFileList =
1974
0
        CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1975
1976
0
    if (papszNewFileList == nullptr)
1977
0
        return CE_Failure;
1978
1979
0
    for (int i = 0; papszFileList[i] != nullptr; ++i)
1980
0
    {
1981
0
        if (CPLCopyFile(papszNewFileList[i], papszFileList[i]) != 0)
1982
0
        {
1983
0
            eErr = CE_Failure;
1984
            // Try to put the ones we moved back.
1985
0
            for (--i; i >= 0; --i)
1986
0
                VSIUnlink(papszNewFileList[i]);
1987
0
            break;
1988
0
        }
1989
0
    }
1990
1991
0
    CSLDestroy(papszNewFileList);
1992
0
    CSLDestroy(papszFileList);
1993
1994
0
    return eErr;
1995
0
}
1996
1997
//! @endcond
1998
1999
/************************************************************************/
2000
/*                             CopyFiles()                              */
2001
/************************************************************************/
2002
2003
/**
2004
 * \brief Copy the files of a dataset.
2005
 *
2006
 * Copy all the files associated with a dataset.
2007
 *
2008
 * Equivalent of the C function GDALCopyDatasetFiles().
2009
 *
2010
 * @param pszNewName new name for the dataset.
2011
 * @param pszOldName old name for the dataset.
2012
 *
2013
 * @return CE_None on success, or CE_Failure if the operation fails.
2014
 */
2015
2016
CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
2017
2018
0
{
2019
0
    pfnCopyFiles = GetCopyFilesCallback();
2020
0
    if (pfnCopyFiles != nullptr)
2021
0
        return pfnCopyFiles(pszNewName, pszOldName);
2022
2023
0
    return DefaultCopyFiles(pszNewName, pszOldName);
2024
0
}
2025
2026
/************************************************************************/
2027
/*                        GDALCopyDatasetFiles()                        */
2028
/************************************************************************/
2029
2030
/**
2031
 * \brief Copy the files of a dataset.
2032
 *
2033
 * @see GDALDriver::CopyFiles()
2034
 */
2035
2036
CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
2037
                                        const char *pszNewName,
2038
                                        const char *pszOldName)
2039
2040
0
{
2041
0
    if (hDriver == nullptr)
2042
0
        hDriver = GDALIdentifyDriver(pszOldName, nullptr);
2043
2044
0
    if (hDriver == nullptr)
2045
0
    {
2046
0
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
2047
0
                 pszOldName);
2048
0
        return CE_Failure;
2049
0
    }
2050
2051
0
    return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
2052
0
}
2053
2054
/************************************************************************/
2055
/*                      GDALDriverHasOpenOption()                       */
2056
/************************************************************************/
2057
2058
/**
2059
 * \brief Returns TRUE if the given open option is supported by the driver.
2060
 * @param hDriver the handle of the driver
2061
 * @param pszOpenOptionName name of the open option to be checked
2062
 * @return TRUE if the driver supports the open option
2063
 * @since GDAL 3.11
2064
 */
2065
bool GDALDriverHasOpenOption(GDALDriverH hDriver, const char *pszOpenOptionName)
2066
0
{
2067
0
    VALIDATE_POINTER1(hDriver, "GDALDriverHasOpenOption", false);
2068
0
    return GDALDriver::FromHandle(hDriver)->HasOpenOption(pszOpenOptionName);
2069
0
}
2070
2071
/************************************************************************/
2072
/*                       GDALGetDriverShortName()                       */
2073
/************************************************************************/
2074
2075
/**
2076
 * \brief Return the short name of a driver
2077
 *
2078
 * This is the string that can be
2079
 * passed to the GDALGetDriverByName() function.
2080
 *
2081
 * For the GeoTIFF driver, this is "GTiff"
2082
 *
2083
 * @param hDriver the handle of the driver
2084
 * @return the short name of the driver. The
2085
 *         returned string should not be freed and is owned by the driver.
2086
 */
2087
2088
const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2089
2090
0
{
2091
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2092
2093
0
    return GDALDriver::FromHandle(hDriver)->GetDescription();
2094
0
}
2095
2096
/************************************************************************/
2097
/*                       GDALGetDriverLongName()                        */
2098
/************************************************************************/
2099
2100
/**
2101
 * \brief Return the long name of a driver
2102
 *
2103
 * For the GeoTIFF driver, this is "GeoTIFF"
2104
 *
2105
 * @param hDriver the handle of the driver
2106
 * @return the long name of the driver or empty string. The
2107
 *         returned string should not be freed and is owned by the driver.
2108
 */
2109
2110
const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2111
2112
0
{
2113
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2114
2115
0
    const char *pszLongName =
2116
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2117
2118
0
    if (pszLongName == nullptr)
2119
0
        return "";
2120
2121
0
    return pszLongName;
2122
0
}
2123
2124
/************************************************************************/
2125
/*                       GDALGetDriverHelpTopic()                       */
2126
/************************************************************************/
2127
2128
/**
2129
 * \brief Return the URL to the help that describes the driver
2130
 *
2131
 * That URL is relative to the GDAL documentation directory.
2132
 *
2133
 * For the GeoTIFF driver, this is "frmt_gtiff.html"
2134
 *
2135
 * @param hDriver the handle of the driver
2136
 * @return the URL to the help that describes the driver or NULL. The
2137
 *         returned string should not be freed and is owned by the driver.
2138
 */
2139
2140
const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
2141
2142
0
{
2143
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
2144
2145
0
    return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2146
0
}
2147
2148
/************************************************************************/
2149
/*                  GDALGetDriverCreationOptionList()                   */
2150
/************************************************************************/
2151
2152
/**
2153
 * \brief Return the list of creation options of the driver
2154
 *
2155
 * Return the list of creation options of the driver used by Create() and
2156
 * CreateCopy() as an XML string
2157
 *
2158
 * @param hDriver the handle of the driver
2159
 * @return an XML string that describes the list of creation options or
2160
 *         empty string. The returned string should not be freed and is
2161
 *         owned by the driver.
2162
 */
2163
2164
const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
2165
2166
0
{
2167
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
2168
2169
0
    const char *pszOptionList =
2170
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2171
0
            GDAL_DMD_CREATIONOPTIONLIST);
2172
2173
0
    if (pszOptionList == nullptr)
2174
0
        return "";
2175
2176
0
    return pszOptionList;
2177
0
}
2178
2179
/************************************************************************/
2180
/*                    GDALValidateCreationOptions()                     */
2181
/************************************************************************/
2182
2183
/**
2184
 * \brief Validate the list of creation options that are handled by a driver
2185
 *
2186
 * This is a helper method primarily used by Create() and
2187
 * CreateCopy() to validate that the passed in list of creation options
2188
 * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2189
 * by some drivers. @see GDALGetDriverCreationOptionList()
2190
 *
2191
 * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2192
 * function will return TRUE. Otherwise it will check that the keys and values
2193
 * in the list of creation options are compatible with the capabilities declared
2194
 * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2195
 * a (non fatal) warning will be emitted and FALSE will be returned.
2196
 *
2197
 * @param hDriver the handle of the driver with whom the lists of creation
2198
 * option must be validated
2199
 * @param papszCreationOptions the list of creation options. An array of
2200
 * strings, whose last element is a NULL pointer
2201
 * @return TRUE if the list of creation options is compatible with the Create()
2202
 *         and CreateCopy() method of the driver, FALSE otherwise.
2203
 */
2204
2205
int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2206
                                            CSLConstList papszCreationOptions)
2207
0
{
2208
0
    VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2209
0
    const char *pszOptionList =
2210
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2211
0
            GDAL_DMD_CREATIONOPTIONLIST);
2212
0
    CPLString osDriver;
2213
0
    osDriver.Printf("driver %s",
2214
0
                    GDALDriver::FromHandle(hDriver)->GetDescription());
2215
0
    bool bFoundOptionToRemove = false;
2216
0
    constexpr const char *const apszExcludedOptions[] = {
2217
0
        "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2218
0
    for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2219
0
    {
2220
0
        for (const char *pszExcludedOptions : apszExcludedOptions)
2221
0
        {
2222
0
            if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2223
0
                pszCO[strlen(pszExcludedOptions)] == '=')
2224
0
            {
2225
0
                bFoundOptionToRemove = true;
2226
0
                break;
2227
0
            }
2228
0
        }
2229
0
        if (bFoundOptionToRemove)
2230
0
            break;
2231
0
    }
2232
0
    CSLConstList papszOptionsToValidate = papszCreationOptions;
2233
0
    char **papszOptionsToFree = nullptr;
2234
0
    if (bFoundOptionToRemove)
2235
0
    {
2236
0
        for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2237
0
        {
2238
0
            bool bMatch = false;
2239
0
            for (const char *pszExcludedOptions : apszExcludedOptions)
2240
0
            {
2241
0
                if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2242
0
                    pszCO[strlen(pszExcludedOptions)] == '=')
2243
0
                {
2244
0
                    bMatch = true;
2245
0
                    break;
2246
0
                }
2247
0
            }
2248
0
            if (!bMatch)
2249
0
                papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
2250
0
        }
2251
0
        papszOptionsToValidate = papszOptionsToFree;
2252
0
    }
2253
2254
0
    const bool bRet = CPL_TO_BOOL(GDALValidateOptions(
2255
0
        pszOptionList, papszOptionsToValidate, "creation option", osDriver));
2256
0
    CSLDestroy(papszOptionsToFree);
2257
0
    return bRet;
2258
0
}
2259
2260
/************************************************************************/
2261
/*                      GDALValidateOpenOptions()                       */
2262
/************************************************************************/
2263
2264
int GDALValidateOpenOptions(GDALDriverH hDriver,
2265
                            const char *const *papszOpenOptions)
2266
0
{
2267
0
    VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2268
0
    const char *pszOptionList =
2269
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2270
0
            GDAL_DMD_OPENOPTIONLIST);
2271
0
    CPLString osDriver;
2272
0
    osDriver.Printf("driver %s",
2273
0
                    GDALDriver::FromHandle(hDriver)->GetDescription());
2274
0
    return GDALValidateOptions(pszOptionList, papszOpenOptions, "open option",
2275
0
                               osDriver);
2276
0
}
2277
2278
/************************************************************************/
2279
/*                        GDALValidateOptions()                         */
2280
/************************************************************************/
2281
2282
int GDALValidateOptions(const char *pszOptionList,
2283
                        const char *const *papszOptionsToValidate,
2284
                        const char *pszErrorMessageOptionType,
2285
                        const char *pszErrorMessageContainerName)
2286
0
{
2287
0
    if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2288
0
        return TRUE;
2289
0
    if (pszOptionList == nullptr)
2290
0
        return TRUE;
2291
2292
0
    CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2293
0
    if (psNode == nullptr)
2294
0
    {
2295
0
        CPLError(CE_Warning, CPLE_AppDefined,
2296
0
                 "Could not parse %s list of %s. Assuming options are valid.",
2297
0
                 pszErrorMessageOptionType, pszErrorMessageContainerName);
2298
0
        return TRUE;
2299
0
    }
2300
2301
0
    bool bRet = true;
2302
0
    while (*papszOptionsToValidate)
2303
0
    {
2304
0
        char *pszKey = nullptr;
2305
0
        const char *pszValue =
2306
0
            CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2307
0
        if (pszKey == nullptr)
2308
0
        {
2309
0
            CPLError(CE_Warning, CPLE_NotSupported,
2310
0
                     "%s '%s' is not formatted with the key=value format",
2311
0
                     pszErrorMessageOptionType, *papszOptionsToValidate);
2312
0
            bRet = false;
2313
2314
0
            ++papszOptionsToValidate;
2315
0
            continue;
2316
0
        }
2317
2318
0
        if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2319
0
        {
2320
0
            ++papszOptionsToValidate;
2321
0
            CPLFree(pszKey);
2322
0
            continue;
2323
0
        }
2324
2325
        // Must we be forgiving in case of missing option ?
2326
0
        bool bWarnIfMissingKey = true;
2327
0
        if (pszKey[0] == '@')
2328
0
        {
2329
0
            bWarnIfMissingKey = false;
2330
0
            memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2331
0
        }
2332
2333
0
        CPLXMLNode *psChildNode = psNode->psChild;
2334
0
        while (psChildNode)
2335
0
        {
2336
0
            if (EQUAL(psChildNode->pszValue, "OPTION"))
2337
0
            {
2338
0
                const char *pszOptionName =
2339
0
                    CPLGetXMLValue(psChildNode, "name", "");
2340
                /* For option names terminated by wildcard (NITF BLOCKA option
2341
                 * names for example) */
2342
0
                if (strlen(pszOptionName) > 0 &&
2343
0
                    pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2344
0
                    EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2345
0
                {
2346
0
                    break;
2347
0
                }
2348
2349
                /* For option names beginning by a wildcard */
2350
0
                if (pszOptionName[0] == '*' &&
2351
0
                    strlen(pszKey) > strlen(pszOptionName) &&
2352
0
                    EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2353
0
                          pszOptionName + 1))
2354
0
                {
2355
0
                    break;
2356
0
                }
2357
2358
                // For options names with * in the middle
2359
0
                const char *pszStarInOptionName = strchr(pszOptionName, '*');
2360
0
                if (pszStarInOptionName &&
2361
0
                    pszStarInOptionName != pszOptionName &&
2362
0
                    pszStarInOptionName !=
2363
0
                        pszOptionName + strlen(pszOptionName) - 1 &&
2364
0
                    strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2365
0
                                                         pszOptionName) &&
2366
0
                    EQUALN(pszKey, pszOptionName,
2367
0
                           static_cast<size_t>(pszStarInOptionName -
2368
0
                                               pszOptionName)) &&
2369
0
                    EQUAL(pszKey +
2370
0
                              static_cast<size_t>(pszStarInOptionName -
2371
0
                                                  pszOptionName) +
2372
0
                              1,
2373
0
                          pszStarInOptionName + 1))
2374
0
                {
2375
0
                    break;
2376
0
                }
2377
2378
0
                if (EQUAL(pszOptionName, pszKey))
2379
0
                {
2380
0
                    break;
2381
0
                }
2382
0
                const char *pszAlias =
2383
0
                    CPLGetXMLValue(psChildNode, "alias", nullptr);
2384
0
                const char *pszDeprecatedAlias =
2385
0
                    pszAlias ? nullptr
2386
0
                             : CPLGetXMLValue(psChildNode, "deprecated_alias",
2387
0
                                              nullptr);
2388
0
                if (!pszAlias && pszDeprecatedAlias)
2389
0
                    pszAlias = pszDeprecatedAlias;
2390
0
                if (pszAlias && EQUAL(pszAlias, pszKey))
2391
0
                {
2392
0
                    if (pszDeprecatedAlias)
2393
0
                    {
2394
0
                        CPLDebug(
2395
0
                            "GDAL",
2396
0
                            "Using deprecated alias '%s'. New name is '%s'",
2397
0
                            pszAlias, pszOptionName);
2398
0
                    }
2399
0
                    break;
2400
0
                }
2401
0
            }
2402
0
            psChildNode = psChildNode->psNext;
2403
0
        }
2404
0
        if (psChildNode == nullptr)
2405
0
        {
2406
0
            if (bWarnIfMissingKey &&
2407
0
                (!EQUAL(pszErrorMessageOptionType, "open option") ||
2408
0
                 CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2409
0
                              true)))
2410
0
            {
2411
0
                CPLError(CE_Warning, CPLE_NotSupported,
2412
0
                         "%s does not support %s %s",
2413
0
                         pszErrorMessageContainerName,
2414
0
                         pszErrorMessageOptionType, pszKey);
2415
0
                bRet = false;
2416
0
            }
2417
2418
0
            CPLFree(pszKey);
2419
0
            ++papszOptionsToValidate;
2420
0
            continue;
2421
0
        }
2422
2423
0
#ifdef DEBUG
2424
0
        CPLXMLNode *psChildSubNode = psChildNode->psChild;
2425
0
        while (psChildSubNode)
2426
0
        {
2427
0
            if (psChildSubNode->eType == CXT_Attribute)
2428
0
            {
2429
0
                if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2430
0
                      EQUAL(psChildSubNode->pszValue, "alias") ||
2431
0
                      EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2432
0
                      EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2433
0
                      EQUAL(psChildSubNode->pszValue, "description") ||
2434
0
                      EQUAL(psChildSubNode->pszValue, "type") ||
2435
0
                      EQUAL(psChildSubNode->pszValue, "min") ||
2436
0
                      EQUAL(psChildSubNode->pszValue, "max") ||
2437
0
                      EQUAL(psChildSubNode->pszValue, "default") ||
2438
0
                      EQUAL(psChildSubNode->pszValue, "maxsize") ||
2439
0
                      EQUAL(psChildSubNode->pszValue, "required") ||
2440
0
                      EQUAL(psChildSubNode->pszValue, "scope")))
2441
0
                {
2442
                    /* Driver error */
2443
0
                    CPLError(CE_Warning, CPLE_NotSupported,
2444
0
                             "%s : unhandled attribute '%s' for %s %s.",
2445
0
                             pszErrorMessageContainerName,
2446
0
                             psChildSubNode->pszValue, pszKey,
2447
0
                             pszErrorMessageOptionType);
2448
0
                }
2449
0
            }
2450
0
            psChildSubNode = psChildSubNode->psNext;
2451
0
        }
2452
0
#endif
2453
2454
0
        const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2455
0
        const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2456
0
        const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2457
0
        if (pszType != nullptr)
2458
0
        {
2459
0
            if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2460
0
            {
2461
0
                const char *pszValueIter = pszValue;
2462
0
                while (*pszValueIter)
2463
0
                {
2464
0
                    if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2465
0
                          *pszValueIter == '+' || *pszValueIter == '-'))
2466
0
                    {
2467
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2468
0
                                 "'%s' is an unexpected value for %s %s of "
2469
0
                                 "type int.",
2470
0
                                 pszValue, pszKey, pszErrorMessageOptionType);
2471
0
                        bRet = false;
2472
0
                        break;
2473
0
                    }
2474
0
                    ++pszValueIter;
2475
0
                }
2476
0
                if (*pszValueIter == '\0')
2477
0
                {
2478
0
                    if (pszMin && atoi(pszValue) < atoi(pszMin))
2479
0
                    {
2480
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2481
0
                                 "'%s' is an unexpected value for %s %s that "
2482
0
                                 "should be >= %s.",
2483
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2484
0
                                 pszMin);
2485
0
                        bRet = false;
2486
0
                    }
2487
0
                    if (pszMax && atoi(pszValue) > atoi(pszMax))
2488
0
                    {
2489
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2490
0
                                 "'%s' is an unexpected value for %s %s that "
2491
0
                                 "should be <= %s.",
2492
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2493
0
                                 pszMax);
2494
0
                        bRet = false;
2495
0
                    }
2496
0
                }
2497
0
            }
2498
0
            else if (EQUAL(pszType, "UNSIGNED INT"))
2499
0
            {
2500
0
                const char *pszValueIter = pszValue;
2501
0
                while (*pszValueIter)
2502
0
                {
2503
0
                    if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2504
0
                          *pszValueIter == '+'))
2505
0
                    {
2506
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2507
0
                                 "'%s' is an unexpected value for %s %s of "
2508
0
                                 "type unsigned int.",
2509
0
                                 pszValue, pszKey, pszErrorMessageOptionType);
2510
0
                        bRet = false;
2511
0
                        break;
2512
0
                    }
2513
0
                    ++pszValueIter;
2514
0
                }
2515
0
                if (*pszValueIter == '\0')
2516
0
                {
2517
0
                    if (pszMin && atoi(pszValue) < atoi(pszMin))
2518
0
                    {
2519
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2520
0
                                 "'%s' is an unexpected value for %s %s that "
2521
0
                                 "should be >= %s.",
2522
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2523
0
                                 pszMin);
2524
0
                        bRet = false;
2525
0
                    }
2526
0
                    if (pszMax && atoi(pszValue) > atoi(pszMax))
2527
0
                    {
2528
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2529
0
                                 "'%s' is an unexpected value for %s %s that "
2530
0
                                 "should be <= %s.",
2531
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2532
0
                                 pszMax);
2533
0
                        bRet = false;
2534
0
                    }
2535
0
                }
2536
0
            }
2537
0
            else if (EQUAL(pszType, "FLOAT"))
2538
0
            {
2539
0
                char *endPtr = nullptr;
2540
0
                double dfVal = CPLStrtod(pszValue, &endPtr);
2541
0
                if (!(endPtr == nullptr || *endPtr == '\0'))
2542
0
                {
2543
0
                    CPLError(
2544
0
                        CE_Warning, CPLE_NotSupported,
2545
0
                        "'%s' is an unexpected value for %s %s of type float.",
2546
0
                        pszValue, pszKey, pszErrorMessageOptionType);
2547
0
                    bRet = false;
2548
0
                }
2549
0
                else
2550
0
                {
2551
0
                    if (pszMin && dfVal < CPLAtof(pszMin))
2552
0
                    {
2553
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2554
0
                                 "'%s' is an unexpected value for %s %s that "
2555
0
                                 "should be >= %s.",
2556
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2557
0
                                 pszMin);
2558
0
                        bRet = false;
2559
0
                    }
2560
0
                    if (pszMax && dfVal > CPLAtof(pszMax))
2561
0
                    {
2562
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2563
0
                                 "'%s' is an unexpected value for %s %s that "
2564
0
                                 "should be <= %s.",
2565
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2566
0
                                 pszMax);
2567
0
                        bRet = false;
2568
0
                    }
2569
0
                }
2570
0
            }
2571
0
            else if (EQUAL(pszType, "BOOLEAN"))
2572
0
            {
2573
0
                if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2574
0
                      EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2575
0
                      EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2576
0
                {
2577
0
                    CPLError(CE_Warning, CPLE_NotSupported,
2578
0
                             "'%s' is an unexpected value for %s %s of type "
2579
0
                             "boolean.",
2580
0
                             pszValue, pszKey, pszErrorMessageOptionType);
2581
0
                    bRet = false;
2582
0
                }
2583
0
            }
2584
0
            else if (EQUAL(pszType, "STRING-SELECT"))
2585
0
            {
2586
0
                bool bMatchFound = false;
2587
0
                CPLXMLNode *psStringSelect = psChildNode->psChild;
2588
0
                while (psStringSelect)
2589
0
                {
2590
0
                    if (psStringSelect->eType == CXT_Element &&
2591
0
                        EQUAL(psStringSelect->pszValue, "Value"))
2592
0
                    {
2593
0
                        CPLXMLNode *psOptionNode = psStringSelect->psChild;
2594
0
                        while (psOptionNode)
2595
0
                        {
2596
0
                            if (psOptionNode->eType == CXT_Text &&
2597
0
                                EQUAL(psOptionNode->pszValue, pszValue))
2598
0
                            {
2599
0
                                bMatchFound = true;
2600
0
                                break;
2601
0
                            }
2602
0
                            if (psOptionNode->eType == CXT_Attribute &&
2603
0
                                (EQUAL(psOptionNode->pszValue, "alias") ||
2604
0
                                 EQUAL(psOptionNode->pszValue,
2605
0
                                       "deprecated_alias")) &&
2606
0
                                EQUAL(psOptionNode->psChild->pszValue,
2607
0
                                      pszValue))
2608
0
                            {
2609
0
                                bMatchFound = true;
2610
0
                                break;
2611
0
                            }
2612
0
                            psOptionNode = psOptionNode->psNext;
2613
0
                        }
2614
0
                        if (bMatchFound)
2615
0
                            break;
2616
0
                    }
2617
0
                    psStringSelect = psStringSelect->psNext;
2618
0
                }
2619
0
                if (!bMatchFound)
2620
0
                {
2621
0
                    CPLError(CE_Warning, CPLE_NotSupported,
2622
0
                             "'%s' is an unexpected value for %s %s of type "
2623
0
                             "string-select.",
2624
0
                             pszValue, pszKey, pszErrorMessageOptionType);
2625
0
                    bRet = false;
2626
0
                }
2627
0
            }
2628
0
            else if (EQUAL(pszType, "STRING"))
2629
0
            {
2630
0
                const char *pszMaxSize =
2631
0
                    CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2632
0
                if (pszMaxSize != nullptr)
2633
0
                {
2634
0
                    if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2635
0
                    {
2636
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2637
0
                                 "'%s' is of size %d, whereas maximum size for "
2638
0
                                 "%s %s is %d.",
2639
0
                                 pszValue, static_cast<int>(strlen(pszValue)),
2640
0
                                 pszKey, pszErrorMessageOptionType,
2641
0
                                 atoi(pszMaxSize));
2642
0
                        bRet = false;
2643
0
                    }
2644
0
                }
2645
0
            }
2646
0
            else
2647
0
            {
2648
                /* Driver error */
2649
0
                CPLError(CE_Warning, CPLE_NotSupported,
2650
0
                         "%s : type '%s' for %s %s is not recognized.",
2651
0
                         pszErrorMessageContainerName, pszType, pszKey,
2652
0
                         pszErrorMessageOptionType);
2653
0
            }
2654
0
        }
2655
0
        else
2656
0
        {
2657
            /* Driver error */
2658
0
            CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2659
0
                     pszErrorMessageContainerName, pszKey,
2660
0
                     pszErrorMessageOptionType);
2661
0
        }
2662
0
        CPLFree(pszKey);
2663
0
        ++papszOptionsToValidate;
2664
0
    }
2665
2666
0
    CPLDestroyXMLNode(psNode);
2667
0
    return bRet ? TRUE : FALSE;
2668
0
}
2669
2670
/************************************************************************/
2671
/*                         GDALIdentifyDriver()                         */
2672
/************************************************************************/
2673
2674
/**
2675
 * \brief Identify the driver that can open a dataset.
2676
 *
2677
 * This function will try to identify the driver that can open the passed file
2678
 * name by invoking the Identify method of each registered GDALDriver in turn.
2679
 * The first driver that successfully identifies the file name will be returned.
2680
 * If all drivers fail then NULL is returned.
2681
 *
2682
 * In order to reduce the need for such searches to touch the operating system
2683
 * file system machinery, it is possible to give an optional list of files.
2684
 * This is the list of all files at the same level in the file system as the
2685
 * target file, including the target file. The filenames will not include any
2686
 * path components, and are essentially just the output of VSIReadDir() on the
2687
 * parent directory. If the target object does not have filesystem semantics
2688
 * then the file list should be NULL.
2689
 *
2690
 * @param pszFilename the name of the file to access.  In the case of
2691
 * exotic drivers this may not refer to a physical file, but instead contain
2692
 * information for the driver on how to access a dataset.
2693
 *
2694
 * @param papszFileList an array of strings, whose last element is the NULL
2695
 * pointer.  These strings are filenames that are auxiliary to the main
2696
 * filename. The passed value may be NULL.
2697
 *
2698
 * @return A GDALDriverH handle or NULL on failure.  For C++ applications
2699
 * this handle can be cast to a GDALDriver *.
2700
 */
2701
2702
GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2703
                                           CSLConstList papszFileList)
2704
2705
0
{
2706
0
    return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2707
0
}
2708
2709
/************************************************************************/
2710
/*                        GDALIdentifyDriverEx()                        */
2711
/************************************************************************/
2712
2713
/**
2714
 * \brief Identify the driver that can open a dataset.
2715
 *
2716
 * This function will try to identify the driver that can open the passed file
2717
 * name by invoking the Identify method of each registered GDALDriver in turn.
2718
 * The first driver that successfully identifies the file name will be returned.
2719
 * If all drivers fail then NULL is returned.
2720
 *
2721
 * In order to reduce the need for such searches to touch the operating system
2722
 * file system machinery, it is possible to give an optional list of files.
2723
 * This is the list of all files at the same level in the file system as the
2724
 * target file, including the target file. The filenames will not include any
2725
 * path components, and are essentially just the output of VSIReadDir() on the
2726
 * parent directory. If the target object does not have filesystem semantics
2727
 * then the file list should be NULL.
2728
 *
2729
 * @param pszFilename the name of the file to access.  In the case of
2730
 * exotic drivers this may not refer to a physical file, but instead contain
2731
 * information for the driver on how to access a dataset.
2732
 *
2733
 * @param nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2734
 * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2735
 * both kinds are implied.
2736
 *
2737
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2738
 * terminated list of strings with the driver short names that must be
2739
 * considered.
2740
 *
2741
 * @param papszFileList an array of strings, whose last element is the NULL
2742
 * pointer.  These strings are filenames that are auxiliary to the main
2743
 * filename. The passed value may be NULL.
2744
 *
2745
 * @return A GDALDriverH handle or NULL on failure.  For C++ applications
2746
 * this handle can be cast to a GDALDriver *.
2747
 */
2748
2749
GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2750
    const char *pszFilename, unsigned int nIdentifyFlags,
2751
    const char *const *papszAllowedDrivers, const char *const *papszFileList)
2752
0
{
2753
0
    GDALDriverManager *poDM = GetGDALDriverManager();
2754
0
    CPLAssert(nullptr != poDM);
2755
2756
    // If no driver kind is specified, assume all are to be probed.
2757
0
    if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2758
0
        nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2759
2760
0
    GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2761
0
    oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2762
2763
0
    CPLErrorStateBackuper oBackuper;
2764
0
    CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2765
2766
0
    const int nDriverCount = poDM->GetDriverCount();
2767
2768
    // First pass: only use drivers that have a pfnIdentify implementation.
2769
0
    std::vector<GDALDriver *> apoSecondPassDrivers;
2770
0
    for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2771
0
    {
2772
0
        GDALDriver *poDriver = poDM->GetDriver(iDriver);
2773
0
        if (papszAllowedDrivers != nullptr &&
2774
0
            CSLFindString(papszAllowedDrivers,
2775
0
                          GDALGetDriverShortName(poDriver)) == -1)
2776
0
        {
2777
0
            continue;
2778
0
        }
2779
2780
0
        VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2781
2782
0
        if (poDriver->pfnIdentify == nullptr &&
2783
0
            poDriver->pfnIdentifyEx == nullptr)
2784
0
        {
2785
0
            continue;
2786
0
        }
2787
2788
0
        if (papszAllowedDrivers != nullptr &&
2789
0
            CSLFindString(papszAllowedDrivers,
2790
0
                          GDALGetDriverShortName(poDriver)) == -1)
2791
0
            continue;
2792
0
        if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2793
0
            (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2794
0
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2795
0
            continue;
2796
0
        if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2797
0
            (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2798
0
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2799
0
            continue;
2800
2801
0
        if (poDriver->pfnIdentifyEx)
2802
0
        {
2803
0
            if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2804
0
                return poDriver;
2805
0
        }
2806
0
        else
2807
0
        {
2808
0
            const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2809
0
            if (nIdentifyRes > 0)
2810
0
                return poDriver;
2811
0
            if (nIdentifyRes < 0 &&
2812
0
                poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2813
0
            {
2814
                // Not loaded plugin
2815
0
                apoSecondPassDrivers.push_back(poDriver);
2816
0
            }
2817
0
        }
2818
0
    }
2819
2820
    // second pass: try loading plugin drivers
2821
0
    for (auto poDriver : apoSecondPassDrivers)
2822
0
    {
2823
        // Force plugin driver loading
2824
0
        poDriver->GetMetadata();
2825
0
        if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2826
0
            return poDriver;
2827
0
    }
2828
2829
    // third pass: slow method.
2830
0
    for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2831
0
    {
2832
0
        GDALDriver *poDriver = poDM->GetDriver(iDriver);
2833
0
        if (papszAllowedDrivers != nullptr &&
2834
0
            CSLFindString(papszAllowedDrivers,
2835
0
                          GDALGetDriverShortName(poDriver)) == -1)
2836
0
        {
2837
0
            continue;
2838
0
        }
2839
2840
0
        VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2841
2842
0
        if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2843
0
            (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2844
0
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2845
0
            continue;
2846
0
        if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2847
0
            (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2848
0
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2849
0
            continue;
2850
2851
0
        if (poDriver->pfnIdentifyEx != nullptr)
2852
0
        {
2853
0
            if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2854
0
                continue;
2855
0
        }
2856
0
        else if (poDriver->pfnIdentify != nullptr)
2857
0
        {
2858
0
            if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2859
0
                continue;
2860
0
        }
2861
2862
0
        GDALDataset *poDS;
2863
0
        if (poDriver->pfnOpen != nullptr)
2864
0
        {
2865
0
            poDS = poDriver->pfnOpen(&oOpenInfo);
2866
0
            if (poDS != nullptr)
2867
0
            {
2868
0
                delete poDS;
2869
0
                return GDALDriver::ToHandle(poDriver);
2870
0
            }
2871
2872
0
            if (CPLGetLastErrorType() != CE_None)
2873
0
                return nullptr;
2874
0
        }
2875
0
        else if (poDriver->pfnOpenWithDriverArg != nullptr)
2876
0
        {
2877
0
            poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2878
0
            if (poDS != nullptr)
2879
0
            {
2880
0
                delete poDS;
2881
0
                return GDALDriver::ToHandle(poDriver);
2882
0
            }
2883
2884
0
            if (CPLGetLastErrorType() != CE_None)
2885
0
                return nullptr;
2886
0
        }
2887
0
    }
2888
2889
0
    return nullptr;
2890
0
}
2891
2892
/************************************************************************/
2893
/*                          GetMetadataItem()                           */
2894
/************************************************************************/
2895
2896
const char *GDALDriver::GetMetadataItem(const char *pszName,
2897
                                        const char *pszDomain)
2898
0
{
2899
0
    if (pszDomain == nullptr || pszDomain[0] == '\0')
2900
0
    {
2901
0
        if (EQUAL(pszName, GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST))
2902
0
        {
2903
0
            const char *pszVal = GDALMajorObject::GetMetadataItem(pszName, "");
2904
0
            if (pszVal)
2905
0
                return pszVal;
2906
0
            if (GetMetadataItem(GDAL_DCAP_RASTER))
2907
0
            {
2908
0
                auto poDM = GetGDALDriverManager();
2909
0
                auto poGTiffDrv = poDM->GetDriverByName("GTiff");
2910
0
                if (poGTiffDrv)
2911
0
                {
2912
0
                    const char *pszXML =
2913
0
                        poGTiffDrv->GetMetadataItem(pszName, "");
2914
0
                    if (pszXML)
2915
0
                    {
2916
0
                        CPLString osXML(pszXML);
2917
0
                        osXML.replaceAll("<Value>INTERNAL</Value>", "");
2918
0
                        return CPLSPrintf("%s", osXML.c_str());
2919
0
                    }
2920
0
                }
2921
0
            }
2922
0
        }
2923
0
    }
2924
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
2925
0
}
2926
2927
/************************************************************************/
2928
/*                          SetMetadataItem()                           */
2929
/************************************************************************/
2930
2931
CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
2932
                                   const char *pszDomain)
2933
2934
0
{
2935
0
    if (pszDomain == nullptr || pszDomain[0] == '\0')
2936
0
    {
2937
        /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
2938
0
        if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
2939
0
            GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
2940
0
        {
2941
0
            GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
2942
0
        }
2943
        /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
2944
0
        else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
2945
0
                 strchr(pszValue, ' ') == nullptr &&
2946
0
                 GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
2947
0
                     nullptr)
2948
0
        {
2949
0
            GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
2950
0
        }
2951
0
    }
2952
0
    return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
2953
0
}
2954
2955
/************************************************************************/
2956
/*                        InstantiateAlgorithm()                        */
2957
/************************************************************************/
2958
2959
//! @cond Doxygen_Suppress
2960
2961
GDALAlgorithm *
2962
GDALDriver::InstantiateAlgorithm(const std::vector<std::string> &aosPath)
2963
0
{
2964
0
    pfnInstantiateAlgorithm = GetInstantiateAlgorithmCallback();
2965
0
    if (pfnInstantiateAlgorithm)
2966
0
        return pfnInstantiateAlgorithm(aosPath);
2967
0
    return nullptr;
2968
0
}
2969
2970
/************************************************************************/
2971
/*                          DeclareAlgorithm()                          */
2972
/************************************************************************/
2973
2974
void GDALDriver::DeclareAlgorithm(const std::vector<std::string> &aosPath)
2975
0
{
2976
0
    const std::string osDriverName = GetDescription();
2977
0
    auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
2978
2979
0
    if (!singleton.HasDeclaredSubAlgorithm({"driver"}))
2980
0
    {
2981
0
        singleton.DeclareAlgorithm(
2982
0
            {"driver"},
2983
0
            []() -> std::unique_ptr<GDALAlgorithm>
2984
0
            {
2985
0
                return std::make_unique<GDALContainerAlgorithm>(
2986
0
                    "driver", "Command for driver specific operations.");
2987
0
            });
2988
0
    }
2989
2990
0
    std::vector<std::string> path = {"driver",
2991
0
                                     CPLString(osDriverName).tolower()};
2992
0
    if (!singleton.HasDeclaredSubAlgorithm(path))
2993
0
    {
2994
0
        auto lambda = [osDriverName]() -> std::unique_ptr<GDALAlgorithm>
2995
0
        {
2996
0
            auto poDriver =
2997
0
                GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
2998
0
            if (poDriver)
2999
0
            {
3000
0
                const char *pszHelpTopic =
3001
0
                    poDriver->GetMetadataItem(GDAL_DMD_HELPTOPIC);
3002
0
                return std::make_unique<GDALContainerAlgorithm>(
3003
0
                    CPLString(osDriverName).tolower(),
3004
0
                    std::string("Command for ")
3005
0
                        .append(osDriverName)
3006
0
                        .append(" driver specific operations."),
3007
0
                    pszHelpTopic ? std::string("/").append(pszHelpTopic)
3008
0
                                 : std::string());
3009
0
            }
3010
0
            return nullptr;
3011
0
        };
3012
0
        singleton.DeclareAlgorithm(path, std::move(lambda));
3013
0
    }
3014
3015
0
    path.insert(path.end(), aosPath.begin(), aosPath.end());
3016
3017
0
    auto lambda = [osDriverName, aosPath]() -> std::unique_ptr<GDALAlgorithm>
3018
0
    {
3019
0
        auto poDriver =
3020
0
            GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3021
0
        if (poDriver)
3022
0
            return std::unique_ptr<GDALAlgorithm>(
3023
0
                poDriver->InstantiateAlgorithm(aosPath));
3024
0
        return nullptr;
3025
0
    };
3026
3027
0
    singleton.DeclareAlgorithm(path, std::move(lambda));
3028
3029
0
    CPL_IGNORE_RET_VAL(osDriverName);
3030
0
}
3031
3032
//! @endcond
3033
3034
/************************************************************************/
3035
/*                     DoesDriverHandleExtension()                      */
3036
/************************************************************************/
3037
3038
static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
3039
0
{
3040
0
    bool bRet = false;
3041
0
    const char *pszDriverExtensions =
3042
0
        GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
3043
0
    if (pszDriverExtensions)
3044
0
    {
3045
0
        const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
3046
0
        const int nTokens = aosTokens.size();
3047
0
        for (int j = 0; j < nTokens; ++j)
3048
0
        {
3049
0
            if (EQUAL(pszExt, aosTokens[j]))
3050
0
            {
3051
0
                bRet = true;
3052
0
                break;
3053
0
            }
3054
0
        }
3055
0
    }
3056
0
    return bRet;
3057
0
}
3058
3059
/************************************************************************/
3060
/*                      IsOnlyExpectedGDBDrivers()                      */
3061
/************************************************************************/
3062
3063
static bool IsOnlyExpectedGDBDrivers(const CPLStringList &aosDriverNames)
3064
0
{
3065
0
    for (const char *pszDrvName : aosDriverNames)
3066
0
    {
3067
0
        if (!EQUAL(pszDrvName, "OpenFileGDB") &&
3068
0
            !EQUAL(pszDrvName, "FileGDB") && !EQUAL(pszDrvName, "GPSBabel"))
3069
0
        {
3070
0
            return false;
3071
0
        }
3072
0
    }
3073
0
    return true;
3074
0
}
3075
3076
/************************************************************************/
3077
/*                 GDALGetOutputDriversForDatasetName()                 */
3078
/************************************************************************/
3079
3080
/** Return a list of driver short names that are likely candidates for the
3081
 * provided output file name.
3082
 *
3083
 * @param pszDestDataset Output dataset name (might not exist).
3084
 * @param nDatasetTypeFlag GDAL_OF_RASTER, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER
3085
 *                         or a binary-or'ed combination of them
3086
 * @param bSingleMatch Whether a single match is desired, that is to say the
3087
 *                     returned list will contain at most one item, which will
3088
 *                     be the first driver in the order they are registered to
3089
 *                     match the output dataset name. Note that in this mode, if
3090
 *                     nDatasetTypeFlag==GDAL_OF_RASTER and pszDestDataset has
3091
 *                     no extension, GTiff will be selected.
3092
 * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
3093
 *                     true and there are more than 2 candidates.
3094
 * @return NULL terminated list of driver short names.
3095
 * To be freed with CSLDestroy()
3096
 * @since 3.9
3097
 */
3098
char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
3099
                                          int nDatasetTypeFlag,
3100
                                          bool bSingleMatch, bool bEmitWarning)
3101
0
{
3102
0
    CPLStringList aosDriverNames;
3103
0
    CPLStringList aosMissingDriverNames;
3104
3105
0
    std::string osExt = CPLGetExtensionSafe(pszDestDataset);
3106
0
    if (EQUAL(osExt.c_str(), "zip"))
3107
0
    {
3108
0
        const CPLString osLower(CPLString(pszDestDataset).tolower());
3109
0
        if (osLower.endsWith(".shp.zip"))
3110
0
        {
3111
0
            osExt = "shp.zip";
3112
0
        }
3113
0
        else if (osLower.endsWith(".gpkg.zip"))
3114
0
        {
3115
0
            osExt = "gpkg.zip";
3116
0
        }
3117
0
    }
3118
0
    else if (EQUAL(osExt.c_str(), "json"))
3119
0
    {
3120
0
        const CPLString osLower(CPLString(pszDestDataset).tolower());
3121
0
        if (osLower.endsWith(".gdalg.json"))
3122
0
            return nullptr;
3123
0
    }
3124
3125
0
    auto poDM = GetGDALDriverManager();
3126
0
    const int nDriverCount = poDM->GetDriverCount(true);
3127
0
    GDALDriver *poMissingPluginDriver = nullptr;
3128
0
    std::string osMatchingPrefix;
3129
0
    for (int i = 0; i < nDriverCount; i++)
3130
0
    {
3131
0
        GDALDriver *poDriver = poDM->GetDriver(i, true);
3132
0
        bool bOk = false;
3133
0
        if ((poDriver->GetMetadataItem(GDAL_DCAP_CREATE) != nullptr ||
3134
0
             poDriver->GetMetadataItem(GDAL_DCAP_CREATECOPY) != nullptr ||
3135
0
             poDriver->GetMetadataItem(GDAL_DCAP_UPDATE) != nullptr) &&
3136
0
            (((nDatasetTypeFlag & GDAL_OF_RASTER) &&
3137
0
              poDriver->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr) ||
3138
0
             ((nDatasetTypeFlag & GDAL_OF_VECTOR) &&
3139
0
              poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr) ||
3140
0
             ((nDatasetTypeFlag & GDAL_OF_MULTIDIM_RASTER) &&
3141
0
              poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) != nullptr)))
3142
0
        {
3143
0
            bOk = true;
3144
0
        }
3145
0
        else if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM) &&
3146
0
                 (nDatasetTypeFlag & GDAL_OF_VECTOR) != 0)
3147
0
        {
3148
0
            bOk = true;
3149
0
        }
3150
0
        if (bOk)
3151
0
        {
3152
0
            if (!osExt.empty() &&
3153
0
                DoesDriverHandleExtension(GDALDriver::ToHandle(poDriver),
3154
0
                                          osExt.c_str()))
3155
0
            {
3156
0
                if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3157
0
                {
3158
0
                    poMissingPluginDriver = poDriver;
3159
0
                    aosMissingDriverNames.AddString(poDriver->GetDescription());
3160
0
                }
3161
0
                else
3162
0
                    aosDriverNames.AddString(poDriver->GetDescription());
3163
0
            }
3164
0
            else
3165
0
            {
3166
0
                const char *pszPrefix =
3167
0
                    poDriver->GetMetadataItem(GDAL_DMD_CONNECTION_PREFIX);
3168
0
                if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
3169
0
                {
3170
0
                    if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3171
0
                    {
3172
0
                        osMatchingPrefix = pszPrefix;
3173
0
                        poMissingPluginDriver = poDriver;
3174
0
                        aosMissingDriverNames.AddString(
3175
0
                            poDriver->GetDescription());
3176
0
                    }
3177
0
                    else
3178
0
                        aosDriverNames.AddString(poDriver->GetDescription());
3179
0
                }
3180
0
            }
3181
0
        }
3182
0
    }
3183
3184
    // GMT is registered before netCDF for opening reasons, but we want
3185
    // netCDF to be used by default for output.
3186
0
    if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
3187
0
        EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
3188
0
    {
3189
0
        aosDriverNames.Clear();
3190
0
        aosDriverNames.AddString("netCDF");
3191
0
        aosDriverNames.AddString("GMT");
3192
0
    }
3193
3194
0
    if (bSingleMatch)
3195
0
    {
3196
0
        if (nDatasetTypeFlag == GDAL_OF_RASTER)
3197
0
        {
3198
0
            if (aosDriverNames.empty())
3199
0
            {
3200
0
                if (osExt.empty())
3201
0
                {
3202
0
                    aosDriverNames.AddString("GTiff");
3203
0
                }
3204
0
            }
3205
0
            else if (aosDriverNames.size() >= 2)
3206
0
            {
3207
0
                if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3208
0
                                      EQUAL(aosDriverNames[1], "COG")))
3209
0
                {
3210
0
                    CPLError(CE_Warning, CPLE_AppDefined,
3211
0
                             "Several drivers matching %s extension. Using %s",
3212
0
                             osExt.c_str(), aosDriverNames[0]);
3213
0
                }
3214
0
                const std::string osDrvName = aosDriverNames[0];
3215
0
                aosDriverNames.Clear();
3216
0
                aosDriverNames.AddString(osDrvName.c_str());
3217
0
            }
3218
0
        }
3219
0
        else if (EQUAL(osExt.c_str(), "gdb") &&
3220
0
                 IsOnlyExpectedGDBDrivers(aosDriverNames))
3221
0
        {
3222
            // Do not warn about that case given that FileGDB write support
3223
            // forwards to OpenFileGDB one. And also consider GPSBabel as too
3224
            // marginal to deserve the warning.
3225
0
            aosDriverNames.Clear();
3226
0
            aosDriverNames.AddString("OpenFileGDB");
3227
0
        }
3228
0
        else if (aosDriverNames.size() >= 2)
3229
0
        {
3230
0
            if (bEmitWarning)
3231
0
            {
3232
0
                CPLError(CE_Warning, CPLE_AppDefined,
3233
0
                         "Several drivers matching %s %s. Using %s",
3234
0
                         osMatchingPrefix.empty() ? osExt.c_str()
3235
0
                                                  : osMatchingPrefix.c_str(),
3236
0
                         osMatchingPrefix.empty() ? "extension" : "prefix",
3237
0
                         aosDriverNames[0]);
3238
0
            }
3239
0
            const std::string osDrvName = aosDriverNames[0];
3240
0
            aosDriverNames.Clear();
3241
0
            aosDriverNames.AddString(osDrvName.c_str());
3242
0
        }
3243
0
    }
3244
3245
0
    if (aosDriverNames.empty() && bEmitWarning &&
3246
0
        aosMissingDriverNames.size() == 1 && poMissingPluginDriver)
3247
0
    {
3248
0
        CPLError(CE_Failure, CPLE_AppDefined,
3249
0
                 "No installed driver matching %s %s, but %s driver is "
3250
0
                 "known. However plugin %s",
3251
0
                 osMatchingPrefix.empty() ? osExt.c_str()
3252
0
                                          : osMatchingPrefix.c_str(),
3253
0
                 osMatchingPrefix.empty() ? "extension" : "prefix",
3254
0
                 poMissingPluginDriver->GetDescription(),
3255
0
                 GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver)
3256
0
                     .c_str());
3257
0
    }
3258
0
    else if (aosDriverNames.empty() && bEmitWarning &&
3259
0
             aosMissingDriverNames.empty())
3260
0
    {
3261
0
        for (const auto &sConnectionPrefix : asKnownConnectionPrefixes)
3262
0
        {
3263
0
            if (STARTS_WITH_CI(pszDestDataset, sConnectionPrefix.pszPrefix))
3264
0
            {
3265
0
                CPLError(CE_Failure, CPLE_AppDefined,
3266
0
                         "Filename %s starts with the connection prefix of "
3267
0
                         "driver %s, which is not enabled in this GDAL build. "
3268
0
                         "If that filename is really intended, explicitly "
3269
0
                         "specify its output format.",
3270
0
                         pszDestDataset, sConnectionPrefix.pszDriverName);
3271
0
                break;
3272
0
            }
3273
0
        }
3274
0
    }
3275
3276
0
    return aosDriverNames.StealList();
3277
0
}
3278
3279
/************************************************************************/
3280
/*               GDALGetMessageAboutMissingPluginDriver()               */
3281
/************************************************************************/
3282
3283
std::string
3284
GDALGetMessageAboutMissingPluginDriver(GDALDriver *poMissingPluginDriver)
3285
0
{
3286
0
    std::string osMsg =
3287
0
        poMissingPluginDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME");
3288
0
    osMsg += " is not available in your "
3289
0
             "installation.";
3290
0
    if (const char *pszInstallationMsg = poMissingPluginDriver->GetMetadataItem(
3291
0
            GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
3292
0
    {
3293
0
        osMsg += " ";
3294
0
        osMsg += pszInstallationMsg;
3295
0
    }
3296
3297
0
    VSIStatBuf sStat;
3298
0
    if (const char *pszGDALDriverPath =
3299
0
            CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr))
3300
0
    {
3301
0
        if (VSIStat(pszGDALDriverPath, &sStat) != 0)
3302
0
        {
3303
0
            if (osMsg.back() != '.')
3304
0
                osMsg += ".";
3305
0
            osMsg += " Directory '";
3306
0
            osMsg += pszGDALDriverPath;
3307
0
            osMsg += "' pointed by GDAL_DRIVER_PATH does not exist.";
3308
0
        }
3309
0
    }
3310
0
    else
3311
0
    {
3312
0
        if (osMsg.back() != '.')
3313
0
            osMsg += ".";
3314
#ifdef INSTALL_PLUGIN_FULL_DIR
3315
        if (VSIStat(INSTALL_PLUGIN_FULL_DIR, &sStat) != 0)
3316
        {
3317
            osMsg += " Directory '";
3318
            osMsg += INSTALL_PLUGIN_FULL_DIR;
3319
            osMsg += "' hardcoded in the GDAL library does not "
3320
                     "exist and the GDAL_DRIVER_PATH "
3321
                     "configuration option is not set.";
3322
        }
3323
        else
3324
#endif
3325
0
        {
3326
0
            osMsg += " The GDAL_DRIVER_PATH configuration "
3327
0
                     "option is not set.";
3328
0
        }
3329
0
    }
3330
0
    return osMsg;
3331
0
}
3332
3333
/************************************************************************/
3334
/*                       GDALClearMemoryCaches()                        */
3335
/************************************************************************/
3336
3337
/**
3338
 * \brief Clear all GDAL-controlled in-memory caches.
3339
 *
3340
 * Iterates registered drivers and calls their pfnClearCaches callback if set,
3341
 * then calls VSICurlClearCache() to clear /vsicurl/ and related caches.
3342
 *
3343
 * Note that neither the global raster block cache or caches specific to open
3344
 * dataset objects are not cleared by this function (in its current implementation).
3345
 *
3346
 * Useful when remote datasets may have changed during the lifetime of a
3347
 * process.
3348
 *
3349
 * @since GDAL 3.13
3350
 */
3351
void GDALClearMemoryCaches()
3352
0
{
3353
0
    auto *poDM = GetGDALDriverManager();
3354
0
    if (poDM)
3355
0
    {
3356
0
        for (int i = 0; i < poDM->GetDriverCount(); i++)
3357
0
        {
3358
0
            auto *poDriver = poDM->GetDriver(i);
3359
0
            if (poDriver && poDriver->pfnClearCaches)
3360
0
                poDriver->pfnClearCaches(poDriver);
3361
0
        }
3362
0
    }
3363
0
    VSICurlClearCache();
3364
0
}