Coverage Report

Created: 2026-07-25 06:50

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(GDALDriver::ToHandle(this), pszOptionList,
397
0
                            papszOptions, "creation option", 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[] = {GDALMD_NBITS, GDAL_MDD_IMAGE_STRUCTURE,
667
0
                                        "PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE,
668
0
                                        nullptr};
669
670
0
    for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
671
0
         iOptItem += 2)
672
0
    {
673
        // does the source have this metadata item on the first band?
674
0
        auto poBand = poSrcDS->GetRasterBand(1);
675
0
        poBand->EnablePixelTypeSignedByteWarning(false);
676
0
        const char *pszValue = poBand->GetMetadataItem(
677
0
            apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
678
0
        poBand->EnablePixelTypeSignedByteWarning(true);
679
680
0
        if (pszValue == nullptr)
681
0
            continue;
682
683
        // Do not override provided value.
684
0
        if (CSLFetchNameValue(papszCreateOptions, pszValue) != nullptr)
685
0
            continue;
686
687
        // Does this appear to be a supported creation option on this driver?
688
0
        const char *pszOptionList =
689
0
            GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
690
691
0
        if (pszOptionList == nullptr ||
692
0
            strstr(pszOptionList, apszOptItems[iOptItem]) == nullptr)
693
0
            continue;
694
695
0
        papszCreateOptions = CSLSetNameValue(papszCreateOptions,
696
0
                                             apszOptItems[iOptItem], pszValue);
697
0
    }
698
699
    /* -------------------------------------------------------------------- */
700
    /*      Create destination dataset.                                     */
701
    /* -------------------------------------------------------------------- */
702
0
    GDALDataType eType = GDT_Unknown;
703
704
0
    if (nBands > 0)
705
0
        eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
706
0
    GDALDataset *poDstDS =
707
0
        Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
708
709
0
    CSLDestroy(papszCreateOptions);
710
711
0
    if (poDstDS == nullptr)
712
0
        return nullptr;
713
714
0
    int nDstBands = poDstDS->GetRasterCount();
715
0
    CPLErr eErr = CE_None;
716
0
    if (nDstBands != nBands)
717
0
    {
718
0
        if (GetMetadataItem(GDAL_DCAP_RASTER) != nullptr)
719
0
        {
720
            // Should not happen for a well-behaved driver.
721
0
            CPLError(
722
0
                CE_Failure, CPLE_AppDefined,
723
0
                "Output driver created only %d bands whereas %d were expected",
724
0
                nDstBands, nBands);
725
0
            eErr = CE_Failure;
726
0
        }
727
0
        nDstBands = 0;
728
0
    }
729
730
    /* -------------------------------------------------------------------- */
731
    /*      Try setting the projection and geotransform if it seems         */
732
    /*      suitable.                                                       */
733
    /* -------------------------------------------------------------------- */
734
0
    if (nDstBands == 0 && !bStrict)
735
0
        CPLTurnFailureIntoWarning(true);
736
737
0
    GDALGeoTransform gt;
738
0
    if (eErr == CE_None && poSrcDS->GetGeoTransform(gt) == CE_None &&
739
0
        gt != GDALGeoTransform())
740
0
    {
741
0
        eErr = poDstDS->SetGeoTransform(gt);
742
0
        if (!bStrict)
743
0
            eErr = CE_None;
744
0
    }
745
746
0
    if (eErr == CE_None)
747
0
    {
748
0
        const auto poSrcSRS = poSrcDS->GetSpatialRefRasterOnly();
749
0
        if (poSrcSRS && !poSrcSRS->IsEmpty())
750
0
        {
751
0
            eErr = poDstDS->SetSpatialRef(poSrcSRS);
752
0
            if (!bStrict)
753
0
                eErr = CE_None;
754
0
        }
755
0
    }
756
757
    /* -------------------------------------------------------------------- */
758
    /*      Copy GCPs.                                                      */
759
    /* -------------------------------------------------------------------- */
760
0
    if (poSrcDS->GetGCPCount() > 0 && eErr == CE_None)
761
0
    {
762
0
        eErr = poDstDS->SetGCPs(poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(),
763
0
                                poSrcDS->GetGCPProjection());
764
0
        if (!bStrict)
765
0
            eErr = CE_None;
766
0
    }
767
768
0
    if (nDstBands == 0 && !bStrict)
769
0
        CPLTurnFailureIntoWarning(false);
770
771
    /* -------------------------------------------------------------------- */
772
    /*      Copy metadata.                                                  */
773
    /* -------------------------------------------------------------------- */
774
0
    DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
775
776
    /* -------------------------------------------------------------------- */
777
    /*      Loop copying bands.                                             */
778
    /* -------------------------------------------------------------------- */
779
0
    for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
780
0
    {
781
0
        GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
782
0
        GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
783
784
        /* --------------------------------------------------------------------
785
         */
786
        /*      Do we need to copy a colortable. */
787
        /* --------------------------------------------------------------------
788
         */
789
0
        GDALColorTable *const poCT = poSrcBand->GetColorTable();
790
0
        if (poCT != nullptr)
791
0
            poDstBand->SetColorTable(poCT);
792
793
        /* --------------------------------------------------------------------
794
         */
795
        /*      Do we need to copy other metadata?  Most of this is */
796
        /*      non-critical, so lets not bother folks if it fails are we */
797
        /*      are not in strict mode. */
798
        /* --------------------------------------------------------------------
799
         */
800
0
        if (!bStrict)
801
0
            CPLTurnFailureIntoWarning(true);
802
803
0
        if (strlen(poSrcBand->GetDescription()) > 0)
804
0
            poDstBand->SetDescription(poSrcBand->GetDescription());
805
806
0
        if (CSLCount(poSrcBand->GetMetadata()) > 0)
807
0
            poDstBand->SetMetadata(poSrcBand->GetMetadata());
808
809
0
        int bSuccess = FALSE;
810
0
        double dfValue = poSrcBand->GetOffset(&bSuccess);
811
0
        if (bSuccess && dfValue != 0.0)
812
0
            poDstBand->SetOffset(dfValue);
813
814
0
        dfValue = poSrcBand->GetScale(&bSuccess);
815
0
        if (bSuccess && dfValue != 1.0)
816
0
            poDstBand->SetScale(dfValue);
817
818
0
        GDALCopyNoDataValue(poDstBand, poSrcBand);
819
820
0
        if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
821
0
            poSrcBand->GetColorInterpretation() !=
822
0
                poDstBand->GetColorInterpretation())
823
0
            poDstBand->SetColorInterpretation(
824
0
                poSrcBand->GetColorInterpretation());
825
826
0
        char **papszCatNames = poSrcBand->GetCategoryNames();
827
0
        if (nullptr != papszCatNames)
828
0
            poDstBand->SetCategoryNames(papszCatNames);
829
830
        // Only copy RAT if it is of reasonable size to fit in memory
831
0
        GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
832
0
        if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
833
0
                                        poRAT->GetRowCount() <
834
0
                                    1024 * 1024)
835
0
        {
836
0
            poDstBand->SetDefaultRAT(poRAT);
837
0
        }
838
839
0
        if (!bStrict)
840
0
        {
841
0
            CPLTurnFailureIntoWarning(false);
842
0
        }
843
0
        else
844
0
        {
845
0
            eErr = CPLGetLastErrorType();
846
0
        }
847
0
    }
848
849
    /* -------------------------------------------------------------------- */
850
    /*      Copy image data.                                                */
851
    /* -------------------------------------------------------------------- */
852
0
    if (eErr == CE_None && nDstBands > 0)
853
0
    {
854
0
        const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
855
0
                                                              nullptr};
856
0
        const bool bSkipHoles = CPLTestBool(
857
0
            CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
858
0
        eErr = GDALDatasetCopyWholeRaster(
859
0
            poSrcDS, poDstDS,
860
0
            bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
861
0
            pProgressData);
862
0
    }
863
864
    /* -------------------------------------------------------------------- */
865
    /*      Should we copy some masks over?                                 */
866
    /* -------------------------------------------------------------------- */
867
0
    if (eErr == CE_None && nDstBands > 0)
868
0
        eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
869
870
    /* -------------------------------------------------------------------- */
871
    /*      Copy vector layers                                              */
872
    /* -------------------------------------------------------------------- */
873
0
    if (eErr == CE_None)
874
0
    {
875
0
        if (nLayerCount > 0 && poDstDS->TestCapability(ODsCCreateLayer))
876
0
        {
877
0
            for (int iLayer = 0; iLayer < nLayerCount; ++iLayer)
878
0
            {
879
0
                OGRLayer *poLayer = poSrcDS->GetLayer(iLayer);
880
881
0
                if (poLayer == nullptr)
882
0
                    continue;
883
884
0
                poDstDS->CopyLayer(poLayer, poLayer->GetName(), nullptr);
885
0
            }
886
0
        }
887
0
    }
888
889
    /* -------------------------------------------------------------------- */
890
    /*      Try to cleanup the output dataset if the translation failed.    */
891
    /* -------------------------------------------------------------------- */
892
0
    if (eErr != CE_None)
893
0
    {
894
0
        delete poDstDS;
895
0
        if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
896
0
        {
897
            // Only delete if creating a new file
898
0
            Delete(pszFilename);
899
0
        }
900
0
        return nullptr;
901
0
    }
902
0
    else
903
0
    {
904
0
        CPLErrorReset();
905
0
    }
906
907
0
    return poDstDS;
908
0
}
909
910
/************************************************************************/
911
/*                        DefaultCopyMetadata()                         */
912
/************************************************************************/
913
914
void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
915
                                     CSLConstList papszOptions,
916
                                     CSLConstList papszExcludedDomains)
917
0
{
918
0
    const char *pszCopySrcMDD =
919
0
        CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
920
0
    char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
921
0
    if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
922
0
        papszSrcMDD)
923
0
    {
924
0
        if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
925
0
             CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
926
0
            CSLFindString(papszExcludedDomains, "") < 0 &&
927
0
            CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
928
0
        {
929
0
            if (poSrcDS->GetMetadata() != nullptr)
930
0
                poDstDS->SetMetadata(poSrcDS->GetMetadata());
931
0
        }
932
933
        /* -------------------------------------------------------------------- */
934
        /*      Copy transportable special domain metadata.                     */
935
        /*      It would be nice to copy geolocation, but it is pretty fragile. */
936
        /* -------------------------------------------------------------------- */
937
0
        constexpr const char *apszDefaultDomains[] = {
938
0
            GDAL_MDD_RPC, "xml:XMP", "json:ISIS3", "json:VICAR"};
939
0
        for (const char *pszDomain : apszDefaultDomains)
940
0
        {
941
0
            if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
942
0
                CSLFindString(papszExcludedDomains, pszDomain) < 0)
943
0
            {
944
0
                CSLConstList papszMD = poSrcDS->GetMetadata(pszDomain);
945
0
                if (papszMD)
946
0
                    poDstDS->SetMetadata(papszMD, pszDomain);
947
0
            }
948
0
        }
949
950
0
        if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
951
0
            papszSrcMDD)
952
0
        {
953
0
            for (const char *pszDomain :
954
0
                 CPLStringList(poSrcDS->GetMetadataDomainList()))
955
0
            {
956
0
                if (pszDomain[0] != 0 &&
957
0
                    (!papszSrcMDD ||
958
0
                     CSLFindString(papszSrcMDD, pszDomain) >= 0))
959
0
                {
960
0
                    bool bCanCopy = true;
961
0
                    if (CSLFindString(papszExcludedDomains, pszDomain) >= 0)
962
0
                    {
963
0
                        bCanCopy = false;
964
0
                    }
965
0
                    else
966
0
                    {
967
0
                        for (const char *pszOtherDomain : apszDefaultDomains)
968
0
                        {
969
0
                            if (EQUAL(pszDomain, pszOtherDomain))
970
0
                            {
971
0
                                bCanCopy = false;
972
0
                                break;
973
0
                            }
974
0
                        }
975
0
                        if (!papszSrcMDD)
976
0
                        {
977
0
                            constexpr const char *const apszReservedDomains[] =
978
0
                                {GDAL_MDD_IMAGE_STRUCTURE,
979
0
                                 "DERIVED_SUBDATASETS"};
980
0
                            for (const char *pszOtherDomain :
981
0
                                 apszReservedDomains)
982
0
                            {
983
0
                                if (EQUAL(pszDomain, pszOtherDomain))
984
0
                                {
985
0
                                    bCanCopy = false;
986
0
                                    break;
987
0
                                }
988
0
                            }
989
0
                        }
990
0
                    }
991
0
                    if (bCanCopy)
992
0
                    {
993
0
                        poDstDS->SetMetadata(poSrcDS->GetMetadata(pszDomain),
994
0
                                             pszDomain);
995
0
                    }
996
0
                }
997
0
            }
998
0
        }
999
0
    }
1000
0
    CSLDestroy(papszSrcMDD);
1001
0
}
1002
1003
/************************************************************************/
1004
/*                      QuietDeleteForCreateCopy()                      */
1005
/************************************************************************/
1006
1007
CPLErr GDALDriver::QuietDeleteForCreateCopy(const char *pszFilename,
1008
                                            GDALDataset *poSrcDS)
1009
0
{
1010
    // Someone issuing CreateCopy("foo.tif") on a
1011
    // memory driver doesn't expect files with those names to be deleted
1012
    // on a file system...
1013
    // This is somewhat messy. Ideally there should be a way for the
1014
    // driver to overload the default behavior
1015
0
    if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
1016
        // VRT with empty name is a un-materialized dataset
1017
0
        !(EQUAL(GetDescription(), "VRT") && pszFilename[0] == 0) &&
1018
        // Also exclude database formats for which there's no file list
1019
        // and whose opening might be slow (GeoRaster in particular)
1020
0
        !EQUAL(GetDescription(), "GeoRaster") &&
1021
0
        !EQUAL(GetDescription(), "PostGISRaster"))
1022
0
    {
1023
        /* --------------------------------------------------------------------
1024
         */
1025
        /*      Establish list of files of output dataset if it already
1026
         * exists. */
1027
        /* --------------------------------------------------------------------
1028
         */
1029
0
        std::set<std::string> oSetExistingDestFiles;
1030
0
        {
1031
0
            CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1032
0
            const char *const apszAllowedDrivers[] = {GetDescription(),
1033
0
                                                      nullptr};
1034
0
            auto poExistingOutputDS =
1035
0
                std::unique_ptr<GDALDataset>(GDALDataset::Open(
1036
0
                    pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1037
0
            if (poExistingOutputDS)
1038
0
            {
1039
0
                for (const char *pszFileInList :
1040
0
                     CPLStringList(poExistingOutputDS->GetFileList()))
1041
0
                {
1042
0
                    oSetExistingDestFiles.insert(
1043
0
                        CPLString(pszFileInList).replaceAll('\\', '/'));
1044
0
                }
1045
0
            }
1046
0
        }
1047
1048
        /* --------------------------------------------------------------------
1049
         */
1050
        /*      Check if the source dataset shares some files with the dest
1051
         * one.*/
1052
        /* --------------------------------------------------------------------
1053
         */
1054
0
        std::set<std::string> oSetExistingDestFilesFoundInSource;
1055
0
        if (!oSetExistingDestFiles.empty())
1056
0
        {
1057
0
            CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1058
            // We need to reopen in a temporary dataset for the particular
1059
            // case of overwritten a .tif.ovr file from a .tif
1060
            // If we probe the file list of the .tif, it will then open the
1061
            // .tif.ovr !
1062
0
            const char *const apszAllowedDrivers[] = {
1063
0
                poSrcDS->GetDriver() ? poSrcDS->GetDriver()->GetDescription()
1064
0
                                     : nullptr,
1065
0
                nullptr};
1066
0
            auto poSrcDSTmp = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1067
0
                poSrcDS->GetDescription(), GDAL_OF_RASTER, apszAllowedDrivers,
1068
0
                poSrcDS->papszOpenOptions));
1069
0
            if (poSrcDSTmp)
1070
0
            {
1071
0
                for (const char *pszFileInList :
1072
0
                     CPLStringList(poSrcDSTmp->GetFileList()))
1073
0
                {
1074
0
                    CPLString osFilename(pszFileInList);
1075
0
                    osFilename.replaceAll('\\', '/');
1076
0
                    if (cpl::contains(oSetExistingDestFiles, osFilename))
1077
0
                    {
1078
0
                        oSetExistingDestFilesFoundInSource.insert(
1079
0
                            std::move(osFilename));
1080
0
                    }
1081
0
                }
1082
0
            }
1083
0
        }
1084
1085
        // If the source file(s) and the dest one share some files in
1086
        // common, only remove the files that are *not* in common
1087
0
        if (!oSetExistingDestFilesFoundInSource.empty())
1088
0
        {
1089
0
            for (const std::string &osFilename : oSetExistingDestFiles)
1090
0
            {
1091
0
                if (!cpl::contains(oSetExistingDestFilesFoundInSource,
1092
0
                                   osFilename))
1093
0
                {
1094
0
                    VSIUnlink(osFilename.c_str());
1095
0
                }
1096
0
            }
1097
0
        }
1098
1099
0
        QuietDelete(pszFilename);
1100
0
    }
1101
1102
0
    return CE_None;
1103
0
}
1104
1105
//! @endcond
1106
1107
/************************************************************************/
1108
/*                             CreateCopy()                             */
1109
/************************************************************************/
1110
1111
/**
1112
 * \brief Create a copy of a dataset.
1113
 *
1114
 * This method will attempt to create a copy of a raster dataset with the
1115
 * indicated filename, and in this drivers format.  Band number, size,
1116
 * type, projection, geotransform and so forth are all to be copied from
1117
 * the provided template dataset.
1118
 *
1119
 * Note that many sequential write once formats (such as JPEG and PNG) don't
1120
 * implement the Create() method but do implement this CreateCopy() method.
1121
 * If the driver doesn't implement CreateCopy(), but does implement Create()
1122
 * then the default CreateCopy() mechanism built on calling Create() will
1123
 * be used.
1124
 * So to test if CreateCopy() is available, you can test if GDAL_DCAP_CREATECOPY
1125
 * or GDAL_DCAP_CREATE is set in the GDAL metadata.
1126
 *
1127
 * It is intended that CreateCopy() will often be used with a source dataset
1128
 * which is a virtual dataset allowing configuration of band types, and other
1129
 * information without actually duplicating raster data (see the VRT driver).
1130
 * This is what is done by the gdal_translate utility for example.
1131
 *
1132
 * That function will try to validate the creation option list passed to the
1133
 * driver with the GDALValidateCreationOptions() method. This check can be
1134
 * disabled by defining the configuration option
1135
 * GDAL_VALIDATE_CREATION_OPTIONS=NO.
1136
 *
1137
 * This function copy all metadata from the default domain ("")
1138
 *
1139
 * Even is bStrict is TRUE, only the <b>value</b> of the data is equivalent,
1140
 * but the data layout (INTERLEAVE as PIXEL/LINE/BAND) of the dst dataset is
1141
 * controlled by the papszOptions creation options, and may differ from the
1142
 * poSrcDS src dataset.
1143
 * Starting from GDAL 3.5, if no INTERLEAVE and COMPRESS creation option has
1144
 * been specified in papszOptions, and if the driver supports equivalent
1145
 * interleaving as the src dataset, the CreateCopy() will internally add the
1146
 * proper creation option to get the same data interleaving.
1147
 *
1148
 * After you have finished working with the returned dataset, it is
1149
 * <b>required</b> to close it with GDALClose(). This does not only close the
1150
 * file handle, but also ensures that all the data and metadata has been written
1151
 * to the dataset (GDALFlushCache() is not sufficient for that purpose).
1152
 *
1153
 * For multidimensional datasets, papszOptions can contain array creation
1154
 * options, if they are prefixed with "ARRAY:". \see GDALGroup::CopyFrom()
1155
 * documentation for further details regarding such options.
1156
 *
1157
 * @param pszFilename the name for the new dataset.  UTF-8 encoded.
1158
 * @param poSrcDS the dataset being duplicated.
1159
 * @param bStrict TRUE if the copy must be strictly equivalent, or more
1160
 * normally FALSE indicating that the copy may adapt as needed for the
1161
 * output format.
1162
 * @param papszOptions additional format dependent options controlling
1163
 * creation of the output file.
1164
 * The APPEND_SUBDATASET=YES option can be specified to avoid prior destruction
1165
 * of existing dataset.
1166
 * Starting with GDAL 3.8.0, the following options are recognized by the
1167
 * GTiff, COG, VRT, PNG au JPEG drivers:
1168
 * <ul>
1169
 * <li>COPY_SRC_MDD=AUTO/YES/NO: whether metadata domains of the source dataset
1170
 * should be copied to the destination dataset. In the default AUTO mode, only
1171
 * "safe" domains will be copied, which include the default metadata domain
1172
 * (some drivers may include other domains such as IMD, RPC, GEOLOCATION). When
1173
 * setting YES, all domains will be copied (but a few reserved ones like
1174
 * IMAGE_STRUCTURE or DERIVED_SUBDATASETS). When setting NO, no source metadata
1175
 * will be copied.
1176
 * </li>
1177
 *<li>SRC_MDD=domain_name: which source metadata domain should be copied.
1178
 * This option restricts the list of source metadata domains to be copied
1179
 * (it implies COPY_SRC_MDD=YES if it is not set). This option may be specified
1180
 * as many times as they are source domains. The default metadata domain is the
1181
 * empty string "" ("_DEFAULT_") may also be used when empty string is not practical)
1182
 * </li>
1183
 * </ul>
1184
 * @param pfnProgress a function to be used to report progress of the copy.
1185
 * @param pProgressData application data passed into progress function.
1186
 *
1187
 * @return a pointer to the newly created dataset (may be read-only access).
1188
 */
1189
1190
GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1191
                                    GDALDataset *poSrcDS, int bStrict,
1192
                                    CSLConstList papszOptions,
1193
                                    GDALProgressFunc pfnProgress,
1194
                                    void *pProgressData)
1195
1196
0
{
1197
0
    if (pfnProgress == nullptr)
1198
0
        pfnProgress = GDALDummyProgress;
1199
1200
0
    const int nBandCount = poSrcDS->GetRasterCount();
1201
1202
    /* -------------------------------------------------------------------- */
1203
    /*      If no INTERLEAVE creation option is given, we will try to add   */
1204
    /*      one that matches the current srcDS interleaving                 */
1205
    /* -------------------------------------------------------------------- */
1206
0
    char **papszOptionsToDelete = nullptr;
1207
0
    const char *srcInterleave =
1208
0
        poSrcDS->GetMetadataItem(GDALMD_INTERLEAVE, GDAL_MDD_IMAGE_STRUCTURE);
1209
0
    if (nBandCount > 1 && srcInterleave != nullptr &&
1210
0
        CSLFetchNameValue(papszOptions, GDALMD_INTERLEAVE) == nullptr &&
1211
0
        EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
1212
0
    {
1213
1214
        // look for INTERLEAVE values of the driver
1215
0
        char **interleavesCSL = nullptr;
1216
0
        const char *pszOptionList =
1217
0
            this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1218
0
        CPLXMLNode *xmlNode =
1219
0
            !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
1220
0
        for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
1221
0
             child != nullptr; child = child->psNext)
1222
0
        {
1223
0
            if ((child->eType == CXT_Element) &&
1224
0
                EQUAL(child->pszValue, "Option"))
1225
0
            {
1226
0
                const char *nameAttribute =
1227
0
                    CPLGetXMLValue(child, "name", nullptr);
1228
0
                const bool isInterleaveAttribute =
1229
0
                    nameAttribute && EQUAL(nameAttribute, GDALMD_INTERLEAVE);
1230
0
                if (isInterleaveAttribute)
1231
0
                {
1232
0
                    for (CPLXMLNode *optionChild = child->psChild;
1233
0
                         optionChild != nullptr;
1234
0
                         optionChild = optionChild->psNext)
1235
0
                    {
1236
0
                        if ((optionChild->eType == CXT_Element) &&
1237
0
                            EQUAL(optionChild->pszValue, "Value"))
1238
0
                        {
1239
0
                            CPLXMLNode *optionChildValue = optionChild->psChild;
1240
0
                            if (optionChildValue &&
1241
0
                                (optionChildValue->eType == CXT_Text))
1242
0
                            {
1243
0
                                interleavesCSL = CSLAddString(
1244
0
                                    interleavesCSL, optionChildValue->pszValue);
1245
0
                            }
1246
0
                        }
1247
0
                    }
1248
0
                }
1249
0
            }
1250
0
        }
1251
0
        CPLDestroyXMLNode(xmlNode);
1252
1253
0
        const char *dstInterleaveBand =
1254
0
            (CSLFindString(interleavesCSL, "BAND") >= 0)  ? "BAND"
1255
0
            : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
1256
0
                                                          : nullptr;
1257
0
        const char *dstInterleaveLine =
1258
0
            (CSLFindString(interleavesCSL, "LINE") >= 0)  ? "LINE"
1259
0
            : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
1260
0
                                                          : nullptr;
1261
0
        const char *dstInterleavePixel =
1262
0
            (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
1263
0
            : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
1264
0
                                                          : nullptr;
1265
0
        const char *dstInterleave =
1266
0
            EQUAL(srcInterleave, "BAND")    ? dstInterleaveBand
1267
0
            : EQUAL(srcInterleave, "LINE")  ? dstInterleaveLine
1268
0
            : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
1269
0
                                            : nullptr;
1270
0
        CSLDestroy(interleavesCSL);
1271
1272
0
        if (dstInterleave != nullptr)
1273
0
        {
1274
0
            papszOptionsToDelete = CSLDuplicate(papszOptions);
1275
0
            papszOptionsToDelete = CSLSetNameValue(
1276
0
                papszOptionsToDelete, GDALMD_INTERLEAVE, dstInterleave);
1277
0
            papszOptionsToDelete = CSLSetNameValue(
1278
0
                papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1279
0
            papszOptions = papszOptionsToDelete;
1280
0
        }
1281
0
    }
1282
1283
    /* -------------------------------------------------------------------- */
1284
    /*      Make sure we cleanup if there is an existing dataset of this    */
1285
    /*      name.  But even if that seems to fail we will continue since    */
1286
    /*      it might just be a corrupt file or something.                   */
1287
    /* -------------------------------------------------------------------- */
1288
0
    const bool bAppendSubdataset =
1289
0
        CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false);
1290
    // Note: @QUIET_DELETE_ON_CREATE_COPY is set to NO by the KMLSuperOverlay
1291
    // driver when writing a .kmz file. Also by GDALTranslate() if it has
1292
    // already done a similar job.
1293
0
    if (!bAppendSubdataset &&
1294
0
        CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1295
0
    {
1296
0
        QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1297
0
    }
1298
1299
0
    int iIdxQuietDeleteOnCreateCopy =
1300
0
        CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1301
0
    if (iIdxQuietDeleteOnCreateCopy >= 0)
1302
0
    {
1303
0
        if (papszOptionsToDelete == nullptr)
1304
0
            papszOptionsToDelete = CSLDuplicate(papszOptions);
1305
0
        papszOptionsToDelete = CSLRemoveStrings(
1306
0
            papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1307
0
        papszOptions = papszOptionsToDelete;
1308
0
    }
1309
1310
    /* -------------------------------------------------------------------- */
1311
    /*      If _INTERNAL_DATASET=YES, the returned dataset will not be      */
1312
    /*      registered in the global list of open datasets.                 */
1313
    /* -------------------------------------------------------------------- */
1314
0
    const int iIdxInternalDataset =
1315
0
        CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1316
0
    bool bInternalDataset = false;
1317
0
    if (iIdxInternalDataset >= 0)
1318
0
    {
1319
0
        bInternalDataset =
1320
0
            CPLFetchBool(papszOptions, "_INTERNAL_DATASET", false);
1321
0
        if (papszOptionsToDelete == nullptr)
1322
0
            papszOptionsToDelete = CSLDuplicate(papszOptions);
1323
0
        papszOptionsToDelete = CSLRemoveStrings(
1324
0
            papszOptionsToDelete, iIdxInternalDataset, 1, nullptr);
1325
0
        papszOptions = papszOptionsToDelete;
1326
0
    }
1327
1328
    /* -------------------------------------------------------------------- */
1329
    /*      Validate creation options.                                      */
1330
    /* -------------------------------------------------------------------- */
1331
0
    if (CPLTestBool(
1332
0
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1333
0
    {
1334
0
        auto poSrcGroup = poSrcDS->GetRootGroup();
1335
0
        if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
1336
0
        {
1337
0
            CPLStringList aosDatasetCO;
1338
0
            for (const char *pszOption : cpl::Iterate(papszOptions))
1339
0
            {
1340
0
                if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
1341
0
                    aosDatasetCO.AddString(pszOption);
1342
0
            }
1343
1344
0
            const char *pszOptionList =
1345
0
                GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
1346
0
            CPLString osDriver;
1347
0
            osDriver.Printf("driver %s", GetDescription());
1348
0
            GDALValidateOptions(GDALDriver::ToHandle(this), pszOptionList,
1349
0
                                aosDatasetCO.List(),
1350
0
                                "mulitdim dataset creation option", osDriver);
1351
0
        }
1352
0
        else
1353
0
        {
1354
0
            GDALValidateCreationOptions(this, papszOptions);
1355
0
        }
1356
0
    }
1357
1358
    /* -------------------------------------------------------------------- */
1359
    /*      Advise the source raster that we are going to read it completely */
1360
    /* -------------------------------------------------------------------- */
1361
1362
0
    const int nXSize = poSrcDS->GetRasterXSize();
1363
0
    const int nYSize = poSrcDS->GetRasterYSize();
1364
0
    GDALDataType eDT = GDT_Unknown;
1365
0
    if (nBandCount > 0)
1366
0
    {
1367
0
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1368
0
        if (poSrcBand)
1369
0
            eDT = poSrcBand->GetRasterDataType();
1370
0
    }
1371
0
    poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1372
0
                        nullptr, nullptr);
1373
1374
    /* -------------------------------------------------------------------- */
1375
    /*      If the format provides a CreateCopy() method use that,          */
1376
    /*      otherwise fallback to the internal implementation using the     */
1377
    /*      Create() method.                                                */
1378
    /* -------------------------------------------------------------------- */
1379
0
    GDALDataset *poDstDS = nullptr;
1380
0
    auto l_pfnCreateCopy = GetCreateCopyCallback();
1381
0
    if (l_pfnCreateCopy != nullptr &&
1382
0
        !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1383
0
    {
1384
0
        poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1385
0
                                  const_cast<char **>(papszOptions),
1386
0
                                  pfnProgress, pProgressData);
1387
0
        if (poDstDS != nullptr)
1388
0
        {
1389
0
            if (poDstDS->GetDescription() == nullptr ||
1390
0
                strlen(poDstDS->GetDescription()) == 0)
1391
0
                poDstDS->SetDescription(pszFilename);
1392
1393
0
            if (poDstDS->poDriver == nullptr)
1394
0
                poDstDS->poDriver = this;
1395
1396
0
            if (!bInternalDataset)
1397
0
                poDstDS->AddToDatasetOpenList();
1398
0
        }
1399
0
    }
1400
0
    else
1401
0
    {
1402
0
        poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1403
0
                                    pfnProgress, pProgressData);
1404
0
    }
1405
1406
0
    CSLDestroy(papszOptionsToDelete);
1407
0
    return poDstDS;
1408
0
}
1409
1410
/************************************************************************/
1411
/*                           GDALCreateCopy()                           */
1412
/************************************************************************/
1413
1414
/**
1415
 * \brief Create a copy of a dataset.
1416
 *
1417
 * @see GDALDriver::CreateCopy()
1418
 */
1419
1420
GDALDatasetH CPL_STDCALL GDALCreateCopy(GDALDriverH hDriver,
1421
                                        const char *pszFilename,
1422
                                        GDALDatasetH hSrcDS, int bStrict,
1423
                                        CSLConstList papszOptions,
1424
                                        GDALProgressFunc pfnProgress,
1425
                                        void *pProgressData)
1426
1427
0
{
1428
0
    VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1429
0
    VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1430
1431
0
    return GDALDriver::FromHandle(hDriver)->CreateCopy(
1432
0
        pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1433
0
        pfnProgress, pProgressData);
1434
0
}
1435
1436
/************************************************************************/
1437
/*                       CanVectorTranslateFrom()                       */
1438
/************************************************************************/
1439
1440
/** Returns whether the driver can translate from a vector dataset,
1441
 * using the arguments passed to GDALVectorTranslate() stored in
1442
 * papszVectorTranslateArguments.
1443
 *
1444
 * This is used to determine if the driver supports the VectorTranslateFrom()
1445
 * operation.
1446
 *
1447
 * @param pszDestName Target dataset name
1448
 * @param poSourceDS  Source dataset
1449
 * @param papszVectorTranslateArguments Non-positional arguments passed to
1450
 *                                      GDALVectorTranslate() (may be nullptr)
1451
 * @param[out] ppapszFailureReasons nullptr, or a pointer to an null-terminated
1452
 * array of strings to record the reason(s) for the impossibility.
1453
 * @return true if VectorTranslateFrom() can be called with the same arguments.
1454
 * @since GDAL 3.8
1455
 */
1456
bool GDALDriver::CanVectorTranslateFrom(
1457
    const char *pszDestName, GDALDataset *poSourceDS,
1458
    CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1459
1460
0
{
1461
0
    if (ppapszFailureReasons)
1462
0
    {
1463
0
        *ppapszFailureReasons = nullptr;
1464
0
    }
1465
1466
0
    if (!pfnCanVectorTranslateFrom)
1467
0
    {
1468
0
        if (ppapszFailureReasons)
1469
0
        {
1470
0
            *ppapszFailureReasons = CSLAddString(
1471
0
                nullptr,
1472
0
                "CanVectorTranslateFrom() not implemented for this driver");
1473
0
        }
1474
0
        return false;
1475
0
    }
1476
1477
0
    char **papszFailureReasons = nullptr;
1478
0
    bool bRet = pfnCanVectorTranslateFrom(
1479
0
        pszDestName, poSourceDS, papszVectorTranslateArguments,
1480
0
        ppapszFailureReasons ? ppapszFailureReasons : &papszFailureReasons);
1481
0
    if (!ppapszFailureReasons)
1482
0
    {
1483
0
        for (const char *pszReason :
1484
0
             cpl::Iterate(static_cast<CSLConstList>(papszFailureReasons)))
1485
0
        {
1486
0
            CPLDebug("GDAL", "%s", pszReason);
1487
0
        }
1488
0
        CSLDestroy(papszFailureReasons);
1489
0
    }
1490
0
    return bRet;
1491
0
}
1492
1493
/************************************************************************/
1494
/*                           HasOpenOption()                            */
1495
/************************************************************************/
1496
1497
bool GDALDriver::HasOpenOption(const char *pszOpenOptionName) const
1498
0
{
1499
0
    if (pszOpenOptionName == nullptr)
1500
0
        return false;
1501
1502
    // Const cast is safe here since we are only reading the metadata
1503
0
    auto pszOOMd{const_cast<GDALDriver *>(this)->GetMetadataItem(
1504
0
        GDAL_DMD_OPENOPTIONLIST)};
1505
0
    if (pszOOMd == nullptr)
1506
0
        return false;
1507
1508
0
    const CPLXMLTreeCloser oXml{CPLParseXMLString(pszOOMd)};
1509
0
    for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1510
0
         option = option->psNext)
1511
0
    {
1512
0
        if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1513
0
                  pszOpenOptionName))
1514
0
            return true;
1515
0
    }
1516
0
    return false;
1517
0
}
1518
1519
/************************************************************************/
1520
/*                       HasLayerCreationOption()                       */
1521
/************************************************************************/
1522
1523
bool GDALDriver::HasLayerCreationOption(const char *pszOptionName) const
1524
0
{
1525
0
    if (pszOptionName == nullptr)
1526
0
        return false;
1527
1528
    // Const cast is safe here since we are only reading the metadata
1529
0
    auto pszXML{const_cast<GDALDriver *>(this)->GetMetadataItem(
1530
0
        GDAL_DS_LAYER_CREATIONOPTIONLIST)};
1531
0
    if (pszXML == nullptr)
1532
0
        return false;
1533
1534
0
    const CPLXMLTreeCloser oXml{CPLParseXMLString(pszXML)};
1535
0
    for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1536
0
         option = option->psNext)
1537
0
    {
1538
0
        if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1539
0
                  pszOptionName))
1540
0
            return true;
1541
0
    }
1542
0
    return false;
1543
0
}
1544
1545
/************************************************************************/
1546
/*                        VectorTranslateFrom()                         */
1547
/************************************************************************/
1548
1549
/** Create a copy of a vector dataset, using the arguments passed to
1550
 * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1551
 *
1552
 * This may be implemented by some drivers that can convert from an existing
1553
 * dataset in an optimized way.
1554
 *
1555
 * This is for example used by the PMTiles to convert from MBTiles.
1556
 *
1557
 * @param pszDestName Target dataset name
1558
 * @param poSourceDS  Source dataset
1559
 * @param papszVectorTranslateArguments Non-positional arguments passed to
1560
 *                                      GDALVectorTranslate() (may be nullptr)
1561
 * @param pfnProgress a function to be used to report progress of the copy.
1562
 * @param pProgressData application data passed into progress function.
1563
 * @return a new dataset in case of success, or nullptr in case of error.
1564
 * @since GDAL 3.8
1565
 */
1566
GDALDataset *GDALDriver::VectorTranslateFrom(
1567
    const char *pszDestName, GDALDataset *poSourceDS,
1568
    CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1569
    void *pProgressData)
1570
1571
0
{
1572
0
    if (!pfnVectorTranslateFrom)
1573
0
    {
1574
0
        CPLError(CE_Failure, CPLE_AppDefined,
1575
0
                 "VectorTranslateFrom() not implemented for this driver");
1576
0
        return nullptr;
1577
0
    }
1578
1579
0
    return pfnVectorTranslateFrom(pszDestName, poSourceDS,
1580
0
                                  papszVectorTranslateArguments, pfnProgress,
1581
0
                                  pProgressData);
1582
0
}
1583
1584
/************************************************************************/
1585
/*                            QuietDelete()                             */
1586
/************************************************************************/
1587
1588
/**
1589
 * \brief Delete dataset if found.
1590
 *
1591
 * This is a helper method primarily used by Create() and
1592
 * CreateCopy() to predelete any dataset of the name soon to be
1593
 * created.  It will attempt to delete the named dataset if
1594
 * one is found, otherwise it does nothing.  An error is only
1595
 * returned if the dataset is found but the delete fails.
1596
 *
1597
 * This is a static method and it doesn't matter what driver instance
1598
 * it is invoked on.  It will attempt to discover the correct driver
1599
 * using Identify().
1600
 *
1601
 * @param pszName the dataset name to try and delete.
1602
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1603
 * terminated list of strings with the driver short names that must be
1604
 * considered. (Note: implemented only starting with GDAL 3.4.1)
1605
 * @return CE_None if the dataset does not exist, or is deleted without issues.
1606
 */
1607
1608
CPLErr GDALDriver::QuietDelete(const char *pszName,
1609
                               CSLConstList papszAllowedDrivers)
1610
1611
0
{
1612
0
    VSIStatBufL sStat;
1613
0
    const bool bExists =
1614
0
        VSIStatExL(pszName, &sStat,
1615
0
                   VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1616
1617
0
#ifdef S_ISFIFO
1618
0
    if (bExists && S_ISFIFO(sStat.st_mode))
1619
0
        return CE_None;
1620
0
#endif
1621
1622
0
    GDALDriver *poDriver = nullptr;
1623
0
    if (papszAllowedDrivers)
1624
0
    {
1625
0
        GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
1626
0
        for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
1627
0
        {
1628
0
            GDALDriver *poTmpDriver =
1629
0
                GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
1630
0
            if (poTmpDriver)
1631
0
            {
1632
0
                const bool bIdentifyRes =
1633
0
                    poTmpDriver->pfnIdentifyEx
1634
0
                        ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
1635
0
                              0
1636
0
                        : poTmpDriver->pfnIdentify &&
1637
0
                              poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
1638
0
                if (bIdentifyRes)
1639
0
                {
1640
0
                    poDriver = poTmpDriver;
1641
0
                    break;
1642
0
                }
1643
0
            }
1644
0
        }
1645
0
    }
1646
0
    else
1647
0
    {
1648
0
        CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1649
0
        poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1650
0
    }
1651
1652
0
    if (poDriver == nullptr)
1653
0
        return CE_None;
1654
1655
0
    if (bExists && VSI_ISDIR(sStat.st_mode) &&
1656
0
        (EQUAL(poDriver->GetDescription(), "MapInfo File") ||
1657
0
         EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
1658
0
    {
1659
        // Those drivers are a bit special and handle directories as container
1660
        // of layers, but it is quite common to found other files too, and
1661
        // removing the directory might be non-desirable.
1662
0
        return CE_None;
1663
0
    }
1664
1665
0
    CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
1666
1667
0
    poDriver->pfnDelete = poDriver->GetDeleteCallback();
1668
0
    const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
1669
0
                        poDriver->pfnDeleteDataSource == nullptr;
1670
0
    if (bQuiet)
1671
0
    {
1672
0
        CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1673
0
        return poDriver->Delete(pszName);
1674
0
    }
1675
0
    else
1676
0
    {
1677
0
        return poDriver->Delete(pszName);
1678
0
    }
1679
0
}
1680
1681
/************************************************************************/
1682
/*                               Delete()                               */
1683
/************************************************************************/
1684
1685
/**
1686
 * \brief Delete named dataset.
1687
 *
1688
 * The driver will attempt to delete the named dataset in a driver specific
1689
 * fashion.  Full featured drivers will delete all associated files,
1690
 * database objects, or whatever is appropriate.  The default behavior when
1691
 * no driver specific behavior is provided is to attempt to delete all the
1692
 * files that are returned by GDALGetFileList() on the dataset handle.
1693
 *
1694
 * It is unwise to have open dataset handles on this dataset when it is
1695
 * deleted.
1696
 *
1697
 * Equivalent of the C function GDALDeleteDataset().
1698
 *
1699
 * @param pszFilename name of dataset to delete.
1700
 *
1701
 * @return CE_None on success, or CE_Failure if the operation fails.
1702
 */
1703
1704
CPLErr GDALDriver::Delete(const char *pszFilename)
1705
1706
0
{
1707
0
    pfnDelete = GetDeleteCallback();
1708
0
    if (pfnDelete != nullptr)
1709
0
        return pfnDelete(pszFilename);
1710
0
    else if (pfnDeleteDataSource != nullptr)
1711
0
        return pfnDeleteDataSource(this, pszFilename);
1712
1713
    /* -------------------------------------------------------------------- */
1714
    /*      Collect file list.                                              */
1715
    /* -------------------------------------------------------------------- */
1716
0
    GDALDatasetH hDS = GDALOpenEx(pszFilename, GDAL_OF_VERBOSE_ERROR, nullptr,
1717
0
                                  nullptr, nullptr);
1718
1719
0
    if (hDS == nullptr)
1720
0
    {
1721
0
        if (CPLGetLastErrorNo() == 0)
1722
0
            CPLError(CE_Failure, CPLE_OpenFailed,
1723
0
                     "Unable to open %s to obtain file list.", pszFilename);
1724
1725
0
        return CE_Failure;
1726
0
    }
1727
1728
0
    const CPLStringList aosFileList(GDALGetFileList(hDS));
1729
1730
0
    GDALClose(hDS);
1731
0
    hDS = nullptr;
1732
1733
0
    if (aosFileList.empty())
1734
0
    {
1735
0
        CPLError(CE_Failure, CPLE_NotSupported,
1736
0
                 "Unable to determine files associated with %s, "
1737
0
                 "delete fails.",
1738
0
                 pszFilename);
1739
0
        return CE_Failure;
1740
0
    }
1741
1742
0
    return Delete(nullptr, aosFileList.List());
1743
0
}
1744
1745
/************************************************************************/
1746
/*                               Delete()                               */
1747
/************************************************************************/
1748
1749
/**
1750
 * \brief Delete a currently opened dataset
1751
 *
1752
 * The driver will attempt to delete the passed dataset in a driver specific
1753
 * fashion.  Full featured drivers will delete all associated files,
1754
 * database objects, or whatever is appropriate.  The default behavior when
1755
 * no driver specific behavior is provided is to attempt to delete all the
1756
 * files that are returned by GDALGetFileList() on the dataset handle.
1757
 *
1758
 * Note that this will generally not work on Windows systems that don't accept
1759
 * deleting opened files.
1760
 *
1761
 * At least one of poDS or papszFileList must not be NULL
1762
 *
1763
 * @param poDS dataset to delete, or NULL
1764
 * @param papszFileList File list to delete, typically obtained with
1765
 *                      poDS->GetFileList(), or NULL
1766
 *
1767
 * @return CE_None on success, or CE_Failure if the operation fails.
1768
 *
1769
 * @since 3.12
1770
 */
1771
1772
CPLErr GDALDriver::Delete(GDALDataset *poDS, CSLConstList papszFileList)
1773
1774
0
{
1775
0
    if (poDS)
1776
0
    {
1777
0
        pfnDelete = GetDeleteCallback();
1778
0
        if (pfnDelete != nullptr)
1779
0
            return pfnDelete(poDS->GetDescription());
1780
0
        else if (pfnDeleteDataSource != nullptr)
1781
0
            return pfnDeleteDataSource(this, poDS->GetDescription());
1782
0
    }
1783
1784
    /* -------------------------------------------------------------------- */
1785
    /*      Delete all files.                                               */
1786
    /* -------------------------------------------------------------------- */
1787
0
    CPLErr eErr = CE_None;
1788
0
    for (int i = 0; papszFileList && papszFileList[i]; ++i)
1789
0
    {
1790
0
        if (VSIUnlink(papszFileList[i]) != 0)
1791
0
        {
1792
0
            CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1793
0
                     papszFileList[i], VSIStrerror(errno));
1794
0
            eErr = CE_Failure;
1795
0
        }
1796
0
    }
1797
1798
0
    return eErr;
1799
0
}
1800
1801
/************************************************************************/
1802
/*                         GDALDeleteDataset()                          */
1803
/************************************************************************/
1804
1805
/**
1806
 * \brief Delete named dataset.
1807
 *
1808
 * @see GDALDriver::Delete()
1809
 */
1810
1811
CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
1812
                                     const char *pszFilename)
1813
1814
0
{
1815
0
    if (hDriver == nullptr)
1816
0
        hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1817
1818
0
    if (hDriver == nullptr)
1819
0
    {
1820
0
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1821
0
                 pszFilename);
1822
0
        return CE_Failure;
1823
0
    }
1824
1825
0
#ifdef OGRAPISPY_ENABLED
1826
0
    if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
1827
0
    {
1828
0
        OGRAPISpyDeleteDataSource(hDriver, pszFilename);
1829
0
    }
1830
0
#endif
1831
1832
0
    return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
1833
0
}
1834
1835
/************************************************************************/
1836
/*                           DefaultRename()                            */
1837
/*                                                                      */
1838
/*      The generic implementation based on the file list used when     */
1839
/*      there is no format specific implementation.                     */
1840
/************************************************************************/
1841
1842
//! @cond Doxygen_Suppress
1843
CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
1844
1845
0
{
1846
    /* -------------------------------------------------------------------- */
1847
    /*      Collect file list.                                              */
1848
    /* -------------------------------------------------------------------- */
1849
0
    auto poDS = std::unique_ptr<GDALDataset>(
1850
0
        GDALDataset::Open(pszOldName, GDAL_OF_ALL | GDAL_OF_VERBOSE_ERROR,
1851
0
                          nullptr, nullptr, nullptr));
1852
1853
0
    if (!poDS)
1854
0
    {
1855
0
        if (CPLGetLastErrorNo() == 0)
1856
0
            CPLError(CE_Failure, CPLE_OpenFailed,
1857
0
                     "Unable to open %s to obtain file list.", pszOldName);
1858
1859
0
        return CE_Failure;
1860
0
    }
1861
1862
0
    const CPLStringList aosFileList(poDS->GetFileList());
1863
1864
0
    poDS.reset();
1865
1866
0
    if (aosFileList.empty())
1867
0
    {
1868
0
        CPLError(CE_Failure, CPLE_NotSupported,
1869
0
                 "Unable to determine files associated with %s,\n"
1870
0
                 "rename fails.",
1871
0
                 pszOldName);
1872
1873
0
        return CE_Failure;
1874
0
    }
1875
1876
    /* -------------------------------------------------------------------- */
1877
    /*      Produce a list of new filenames that correspond to the old      */
1878
    /*      names.                                                          */
1879
    /* -------------------------------------------------------------------- */
1880
0
    CPLErr eErr = CE_None;
1881
0
    const CPLStringList aosNewFileList(
1882
0
        CPLCorrespondingPaths(pszOldName, pszNewName, aosFileList.List()));
1883
1884
0
    if (aosNewFileList.empty())
1885
0
        return CE_Failure;
1886
1887
    // Guaranteed by CPLCorrespondingPaths()
1888
0
    CPLAssert(aosNewFileList.size() == aosFileList.size());
1889
1890
0
    VSIStatBufL sStatBuf;
1891
0
    if (VSIStatL(pszOldName, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) &&
1892
0
        VSIStatL(pszNewName, &sStatBuf) != 0)
1893
0
    {
1894
0
        if (VSIMkdirRecursive(pszNewName, 0755) != 0)
1895
0
        {
1896
0
            CPLError(CE_Failure, CPLE_AppDefined,
1897
0
                     "Cannot create directory '%s'", pszNewName);
1898
0
            return CE_Failure;
1899
0
        }
1900
0
    }
1901
1902
0
    for (int i = 0; i < aosFileList.size(); ++i)
1903
0
    {
1904
0
        if (CPLMoveFile(aosNewFileList[i], aosFileList[i]) != 0)
1905
0
        {
1906
            // Above method will have emitted an error in case of failure.
1907
0
            eErr = CE_Failure;
1908
            // Try to put the ones we moved back.
1909
0
            for (--i; i >= 0; i--)
1910
0
            {
1911
                // Nothing we can do if the moving back doesn't work...
1912
0
                CPL_IGNORE_RET_VAL(
1913
0
                    CPLMoveFile(aosFileList[i], aosNewFileList[i]));
1914
0
            }
1915
0
            break;
1916
0
        }
1917
0
    }
1918
1919
0
    return eErr;
1920
0
}
1921
1922
//! @endcond
1923
1924
/************************************************************************/
1925
/*                               Rename()                               */
1926
/************************************************************************/
1927
1928
/**
1929
 * \brief Rename a dataset.
1930
 *
1931
 * Rename a dataset. This may including moving the dataset to a new directory
1932
 * or even a new filesystem.
1933
 *
1934
 * It is unwise to have open dataset handles on this dataset when it is
1935
 * being renamed.
1936
 *
1937
 * Equivalent of the C function GDALRenameDataset().
1938
 *
1939
 * @param pszNewName new name for the dataset.
1940
 * @param pszOldName old name for the dataset.
1941
 *
1942
 * @return CE_None on success, or CE_Failure if the operation fails.
1943
 */
1944
1945
CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
1946
1947
0
{
1948
0
    pfnRename = GetRenameCallback();
1949
0
    if (pfnRename != nullptr)
1950
0
        return pfnRename(pszNewName, pszOldName);
1951
1952
0
    return DefaultRename(pszNewName, pszOldName);
1953
0
}
1954
1955
/************************************************************************/
1956
/*                         GDALRenameDataset()                          */
1957
/************************************************************************/
1958
1959
/**
1960
 * \brief Rename a dataset.
1961
 *
1962
 * @see GDALDriver::Rename()
1963
 */
1964
1965
CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
1966
                                     const char *pszNewName,
1967
                                     const char *pszOldName)
1968
1969
0
{
1970
0
    if (hDriver == nullptr)
1971
0
        hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1972
1973
0
    if (hDriver == nullptr)
1974
0
    {
1975
0
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1976
0
                 pszOldName);
1977
0
        return CE_Failure;
1978
0
    }
1979
1980
0
    return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
1981
0
}
1982
1983
/************************************************************************/
1984
/*                          DefaultCopyFiles()                          */
1985
/*                                                                      */
1986
/*      The default implementation based on file lists used when        */
1987
/*      there is no format specific implementation.                     */
1988
/************************************************************************/
1989
1990
//! @cond Doxygen_Suppress
1991
CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
1992
                                    const char *pszOldName)
1993
1994
0
{
1995
    /* -------------------------------------------------------------------- */
1996
    /*      Collect file list.                                              */
1997
    /* -------------------------------------------------------------------- */
1998
0
    auto poDS = std::unique_ptr<GDALDataset>(
1999
0
        GDALDataset::Open(pszOldName, GDAL_OF_ALL | GDAL_OF_VERBOSE_ERROR,
2000
0
                          nullptr, nullptr, nullptr));
2001
2002
0
    if (!poDS)
2003
0
    {
2004
0
        if (CPLGetLastErrorNo() == 0)
2005
0
            CPLError(CE_Failure, CPLE_OpenFailed,
2006
0
                     "Unable to open %s to obtain file list.", pszOldName);
2007
2008
0
        return CE_Failure;
2009
0
    }
2010
2011
0
    const CPLStringList aosFileList(poDS->GetFileList());
2012
2013
0
    poDS.reset();
2014
2015
0
    if (aosFileList.empty())
2016
0
    {
2017
0
        CPLError(CE_Failure, CPLE_NotSupported,
2018
0
                 "Unable to determine files associated with %s,\n"
2019
0
                 "copy fails.",
2020
0
                 pszOldName);
2021
2022
0
        return CE_Failure;
2023
0
    }
2024
2025
    /* -------------------------------------------------------------------- */
2026
    /*      Produce a list of new filenames that correspond to the old      */
2027
    /*      names.                                                          */
2028
    /* -------------------------------------------------------------------- */
2029
0
    CPLErr eErr = CE_None;
2030
0
    const CPLStringList aosNewFileList(
2031
0
        CPLCorrespondingPaths(pszOldName, pszNewName, aosFileList.List()));
2032
2033
0
    if (aosNewFileList.empty())
2034
0
        return CE_Failure;
2035
2036
    // Guaranteed by CPLCorrespondingPaths()
2037
0
    CPLAssert(aosNewFileList.size() == aosFileList.size());
2038
2039
0
    VSIStatBufL sStatBuf;
2040
0
    if (VSIStatL(pszOldName, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) &&
2041
0
        VSIStatL(pszNewName, &sStatBuf) != 0)
2042
0
    {
2043
0
        if (VSIMkdirRecursive(pszNewName, 0755) != 0)
2044
0
        {
2045
0
            CPLError(CE_Failure, CPLE_AppDefined,
2046
0
                     "Cannot create directory '%s'", pszNewName);
2047
0
            return CE_Failure;
2048
0
        }
2049
0
    }
2050
2051
0
    for (int i = 0; i < aosFileList.size(); ++i)
2052
0
    {
2053
0
        if (CPLCopyFile(aosNewFileList[i], aosFileList[i]) != 0)
2054
0
        {
2055
            // Above method will have emitted an error in case of failure.
2056
0
            eErr = CE_Failure;
2057
            // Try to put the ones we moved back.
2058
0
            for (--i; i >= 0; --i)
2059
0
            {
2060
0
                if (VSIUnlink(aosNewFileList[i]) != 0)
2061
0
                {
2062
0
                    CPLError(CE_Warning, CPLE_AppDefined, "Cannot delete '%s'",
2063
0
                             aosNewFileList[i]);
2064
0
                }
2065
0
            }
2066
0
            break;
2067
0
        }
2068
0
    }
2069
2070
0
    return eErr;
2071
0
}
2072
2073
//! @endcond
2074
2075
/************************************************************************/
2076
/*                             CopyFiles()                              */
2077
/************************************************************************/
2078
2079
/**
2080
 * \brief Copy the files of a dataset.
2081
 *
2082
 * Copy all the files associated with a dataset.
2083
 *
2084
 * Equivalent of the C function GDALCopyDatasetFiles().
2085
 *
2086
 * @param pszNewName new name for the dataset.
2087
 * @param pszOldName old name for the dataset.
2088
 *
2089
 * @return CE_None on success, or CE_Failure if the operation fails.
2090
 */
2091
2092
CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
2093
2094
0
{
2095
0
    pfnCopyFiles = GetCopyFilesCallback();
2096
0
    if (pfnCopyFiles != nullptr)
2097
0
        return pfnCopyFiles(pszNewName, pszOldName);
2098
2099
0
    return DefaultCopyFiles(pszNewName, pszOldName);
2100
0
}
2101
2102
/************************************************************************/
2103
/*                        GDALCopyDatasetFiles()                        */
2104
/************************************************************************/
2105
2106
/**
2107
 * \brief Copy the files of a dataset.
2108
 *
2109
 * @see GDALDriver::CopyFiles()
2110
 */
2111
2112
CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
2113
                                        const char *pszNewName,
2114
                                        const char *pszOldName)
2115
2116
0
{
2117
0
    if (hDriver == nullptr)
2118
0
        hDriver = GDALIdentifyDriver(pszOldName, nullptr);
2119
2120
0
    if (hDriver == nullptr)
2121
0
    {
2122
0
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
2123
0
                 pszOldName);
2124
0
        return CE_Failure;
2125
0
    }
2126
2127
0
    return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
2128
0
}
2129
2130
/************************************************************************/
2131
/*                      GDALDriverHasOpenOption()                       */
2132
/************************************************************************/
2133
2134
/**
2135
 * \brief Returns TRUE if the given open option is supported by the driver.
2136
 * @param hDriver the handle of the driver
2137
 * @param pszOpenOptionName name of the open option to be checked
2138
 * @return TRUE if the driver supports the open option
2139
 * @since GDAL 3.11
2140
 */
2141
bool GDALDriverHasOpenOption(GDALDriverH hDriver, const char *pszOpenOptionName)
2142
0
{
2143
0
    VALIDATE_POINTER1(hDriver, "GDALDriverHasOpenOption", false);
2144
0
    return GDALDriver::FromHandle(hDriver)->HasOpenOption(pszOpenOptionName);
2145
0
}
2146
2147
/************************************************************************/
2148
/*                       GDALGetDriverShortName()                       */
2149
/************************************************************************/
2150
2151
/**
2152
 * \brief Return the short name of a driver
2153
 *
2154
 * This is the string that can be
2155
 * passed to the GDALGetDriverByName() function.
2156
 *
2157
 * For the GeoTIFF driver, this is "GTiff"
2158
 *
2159
 * @param hDriver the handle of the driver
2160
 * @return the short name of the driver. The
2161
 *         returned string should not be freed and is owned by the driver.
2162
 */
2163
2164
const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2165
2166
0
{
2167
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2168
2169
0
    return GDALDriver::FromHandle(hDriver)->GetDescription();
2170
0
}
2171
2172
/************************************************************************/
2173
/*                       GDALGetDriverLongName()                        */
2174
/************************************************************************/
2175
2176
/**
2177
 * \brief Return the long name of a driver
2178
 *
2179
 * For the GeoTIFF driver, this is "GeoTIFF"
2180
 *
2181
 * @param hDriver the handle of the driver
2182
 * @return the long name of the driver or empty string. The
2183
 *         returned string should not be freed and is owned by the driver.
2184
 */
2185
2186
const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2187
2188
0
{
2189
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2190
2191
0
    const char *pszLongName =
2192
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2193
2194
0
    if (pszLongName == nullptr)
2195
0
        return "";
2196
2197
0
    return pszLongName;
2198
0
}
2199
2200
/************************************************************************/
2201
/*                       GDALGetDriverHelpTopic()                       */
2202
/************************************************************************/
2203
2204
/**
2205
 * \brief Return the URL to the help that describes the driver
2206
 *
2207
 * That URL is relative to the GDAL documentation directory.
2208
 *
2209
 * For the GeoTIFF driver, this is "frmt_gtiff.html"
2210
 *
2211
 * @param hDriver the handle of the driver
2212
 * @return the URL to the help that describes the driver or NULL. The
2213
 *         returned string should not be freed and is owned by the driver.
2214
 */
2215
2216
const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
2217
2218
0
{
2219
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
2220
2221
0
    return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2222
0
}
2223
2224
/************************************************************************/
2225
/*                  GDALGetDriverCreationOptionList()                   */
2226
/************************************************************************/
2227
2228
/**
2229
 * \brief Return the list of creation options of the driver
2230
 *
2231
 * Return the list of creation options of the driver used by Create() and
2232
 * CreateCopy() as an XML string
2233
 *
2234
 * @param hDriver the handle of the driver
2235
 * @return an XML string that describes the list of creation options or
2236
 *         empty string. The returned string should not be freed and is
2237
 *         owned by the driver.
2238
 */
2239
2240
const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
2241
2242
0
{
2243
0
    VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
2244
2245
0
    const char *pszOptionList =
2246
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2247
0
            GDAL_DMD_CREATIONOPTIONLIST);
2248
2249
0
    if (pszOptionList == nullptr)
2250
0
        return "";
2251
2252
0
    return pszOptionList;
2253
0
}
2254
2255
/************************************************************************/
2256
/*                    GDALValidateCreationOptions()                     */
2257
/************************************************************************/
2258
2259
/**
2260
 * \brief Validate the list of creation options that are handled by a driver
2261
 *
2262
 * This is a helper method primarily used by Create() and
2263
 * CreateCopy() to validate that the passed in list of creation options
2264
 * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2265
 * by some drivers. @see GDALGetDriverCreationOptionList()
2266
 *
2267
 * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2268
 * function will return TRUE. Otherwise it will check that the keys and values
2269
 * in the list of creation options are compatible with the capabilities declared
2270
 * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2271
 * a (non fatal) warning will be emitted and FALSE will be returned.
2272
 *
2273
 * @param hDriver the handle of the driver with whom the lists of creation
2274
 * option must be validated
2275
 * @param papszCreationOptions the list of creation options. An array of
2276
 * strings, whose last element is a NULL pointer
2277
 * @return TRUE if the list of creation options is compatible with the Create()
2278
 *         and CreateCopy() method of the driver, FALSE otherwise.
2279
 */
2280
2281
int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2282
                                            CSLConstList papszCreationOptions)
2283
0
{
2284
0
    VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2285
0
    const char *pszOptionList =
2286
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2287
0
            GDAL_DMD_CREATIONOPTIONLIST);
2288
0
    CPLString osDriver;
2289
0
    osDriver.Printf("driver %s",
2290
0
                    GDALDriver::FromHandle(hDriver)->GetDescription());
2291
0
    bool bFoundOptionToRemove = false;
2292
0
    constexpr const char *const apszExcludedOptions[] = {
2293
0
        "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2294
0
    for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2295
0
    {
2296
0
        for (const char *pszExcludedOptions : apszExcludedOptions)
2297
0
        {
2298
0
            if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2299
0
                pszCO[strlen(pszExcludedOptions)] == '=')
2300
0
            {
2301
0
                bFoundOptionToRemove = true;
2302
0
                break;
2303
0
            }
2304
0
        }
2305
0
        if (bFoundOptionToRemove)
2306
0
            break;
2307
0
    }
2308
0
    CSLConstList papszOptionsToValidate = papszCreationOptions;
2309
0
    char **papszOptionsToFree = nullptr;
2310
0
    if (bFoundOptionToRemove)
2311
0
    {
2312
0
        for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2313
0
        {
2314
0
            bool bMatch = false;
2315
0
            for (const char *pszExcludedOptions : apszExcludedOptions)
2316
0
            {
2317
0
                if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2318
0
                    pszCO[strlen(pszExcludedOptions)] == '=')
2319
0
                {
2320
0
                    bMatch = true;
2321
0
                    break;
2322
0
                }
2323
0
            }
2324
0
            if (!bMatch)
2325
0
                papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
2326
0
        }
2327
0
        papszOptionsToValidate = papszOptionsToFree;
2328
0
    }
2329
2330
0
    const bool bRet = CPL_TO_BOOL(
2331
0
        GDALValidateOptions(hDriver, pszOptionList, papszOptionsToValidate,
2332
0
                            "creation option", osDriver));
2333
0
    CSLDestroy(papszOptionsToFree);
2334
0
    return bRet;
2335
0
}
2336
2337
/************************************************************************/
2338
/*                      GDALValidateOpenOptions()                       */
2339
/************************************************************************/
2340
2341
int GDALValidateOpenOptions(GDALDriverH hDriver,
2342
                            const char *const *papszOpenOptions)
2343
0
{
2344
0
    VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2345
0
    const char *pszOptionList =
2346
0
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2347
0
            GDAL_DMD_OPENOPTIONLIST);
2348
0
    CPLString osDriver;
2349
0
    osDriver.Printf("driver %s",
2350
0
                    GDALDriver::FromHandle(hDriver)->GetDescription());
2351
0
    return GDALValidateOptions(hDriver, pszOptionList, papszOpenOptions,
2352
0
                               "open option", osDriver);
2353
0
}
2354
2355
/************************************************************************/
2356
/*                        GDALValidateOptions()                         */
2357
/************************************************************************/
2358
2359
int GDALValidateOptions(GDALDriverH hDriver, const char *pszOptionList,
2360
                        const char *const *papszOptionsToValidate,
2361
                        const char *pszErrorMessageOptionType,
2362
                        const char *pszErrorMessageContainerName)
2363
0
{
2364
0
    if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2365
0
        return TRUE;
2366
0
    if (pszOptionList == nullptr)
2367
0
        return TRUE;
2368
2369
0
    CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2370
0
    if (psNode == nullptr)
2371
0
    {
2372
0
        CPLError(CE_Warning, CPLE_AppDefined,
2373
0
                 "Could not parse %s list of %s. Assuming options are valid.",
2374
0
                 pszErrorMessageOptionType, pszErrorMessageContainerName);
2375
0
        return TRUE;
2376
0
    }
2377
2378
0
    bool bRet = true;
2379
0
    while (*papszOptionsToValidate)
2380
0
    {
2381
0
        char *pszKey = nullptr;
2382
0
        const char *pszValue =
2383
0
            CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2384
0
        if (pszKey == nullptr)
2385
0
        {
2386
0
            CPLError(CE_Warning, CPLE_NotSupported,
2387
0
                     "%s '%s' is not formatted with the key=value format",
2388
0
                     pszErrorMessageOptionType, *papszOptionsToValidate);
2389
0
            bRet = false;
2390
2391
0
            ++papszOptionsToValidate;
2392
0
            continue;
2393
0
        }
2394
2395
0
        if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2396
0
        {
2397
0
            ++papszOptionsToValidate;
2398
0
            CPLFree(pszKey);
2399
0
            continue;
2400
0
        }
2401
2402
        // Must we be forgiving in case of missing option ?
2403
0
        bool bWarnIfMissingKey = true;
2404
0
        if (pszKey[0] == '@')
2405
0
        {
2406
0
            bWarnIfMissingKey = false;
2407
0
            memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2408
0
        }
2409
2410
0
        CPLXMLNode *psChildNode = psNode->psChild;
2411
0
        while (psChildNode)
2412
0
        {
2413
0
            if (EQUAL(psChildNode->pszValue, "OPTION"))
2414
0
            {
2415
0
                const char *pszOptionName =
2416
0
                    CPLGetXMLValue(psChildNode, "name", "");
2417
                /* For option names terminated by wildcard (NITF BLOCKA option
2418
                 * names for example) */
2419
0
                if (strlen(pszOptionName) > 0 &&
2420
0
                    pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2421
0
                    EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2422
0
                {
2423
0
                    break;
2424
0
                }
2425
2426
                /* For option names beginning by a wildcard */
2427
0
                if (pszOptionName[0] == '*' &&
2428
0
                    strlen(pszKey) > strlen(pszOptionName) &&
2429
0
                    EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2430
0
                          pszOptionName + 1))
2431
0
                {
2432
0
                    break;
2433
0
                }
2434
2435
                // For options names with * in the middle
2436
0
                const char *pszStarInOptionName = strchr(pszOptionName, '*');
2437
0
                if (pszStarInOptionName &&
2438
0
                    pszStarInOptionName != pszOptionName &&
2439
0
                    pszStarInOptionName !=
2440
0
                        pszOptionName + strlen(pszOptionName) - 1 &&
2441
0
                    strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2442
0
                                                         pszOptionName) &&
2443
0
                    EQUALN(pszKey, pszOptionName,
2444
0
                           static_cast<size_t>(pszStarInOptionName -
2445
0
                                               pszOptionName)) &&
2446
0
                    EQUAL(pszKey +
2447
0
                              static_cast<size_t>(pszStarInOptionName -
2448
0
                                                  pszOptionName) +
2449
0
                              1,
2450
0
                          pszStarInOptionName + 1))
2451
0
                {
2452
0
                    break;
2453
0
                }
2454
2455
0
                if (EQUAL(pszOptionName, pszKey))
2456
0
                {
2457
0
                    break;
2458
0
                }
2459
0
                const char *pszAlias =
2460
0
                    CPLGetXMLValue(psChildNode, "alias", nullptr);
2461
0
                const char *pszDeprecatedAlias =
2462
0
                    pszAlias ? nullptr
2463
0
                             : CPLGetXMLValue(psChildNode, "deprecated_alias",
2464
0
                                              nullptr);
2465
0
                if (!pszAlias && pszDeprecatedAlias)
2466
0
                    pszAlias = pszDeprecatedAlias;
2467
0
                if (pszAlias && EQUAL(pszAlias, pszKey))
2468
0
                {
2469
0
                    if (pszDeprecatedAlias)
2470
0
                    {
2471
0
                        CPLDebug(
2472
0
                            "GDAL",
2473
0
                            "Using deprecated alias '%s'. New name is '%s'",
2474
0
                            pszAlias, pszOptionName);
2475
0
                    }
2476
0
                    break;
2477
0
                }
2478
0
            }
2479
0
            psChildNode = psChildNode->psNext;
2480
0
        }
2481
0
        if (psChildNode == nullptr)
2482
0
        {
2483
0
            if (bWarnIfMissingKey &&
2484
0
                (!EQUAL(pszErrorMessageOptionType, "open option") ||
2485
0
                 CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2486
0
                              true)))
2487
0
            {
2488
0
                const char *pszAdditionalMsg = "";
2489
0
                if (hDriver &&
2490
0
                    EQUAL(pszErrorMessageOptionType, "creation option"))
2491
0
                {
2492
0
                    const char *pszLCOList =
2493
0
                        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2494
0
                            GDAL_DS_LAYER_CREATIONOPTIONLIST);
2495
0
                    if (pszLCOList &&
2496
0
                        (CPLString(pszLCOList)
2497
0
                                 .ifind(CPLSPrintf("\"%s\"", pszKey)) !=
2498
0
                             std::string::npos ||
2499
0
                         CPLString(pszLCOList)
2500
0
                                 .ifind(CPLSPrintf("'%s'", pszKey)) !=
2501
0
                             std::string::npos))
2502
0
                    {
2503
0
                        pszAdditionalMsg = ", but a layer creation option of "
2504
0
                                           "that name exists.";
2505
0
                    }
2506
0
                }
2507
0
                else if (hDriver && EQUAL(pszErrorMessageOptionType,
2508
0
                                          "layer creation option"))
2509
0
                {
2510
0
                    const char *pszLCOList =
2511
0
                        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2512
0
                            GDAL_DMD_CREATIONOPTIONLIST);
2513
0
                    if (pszLCOList &&
2514
0
                        (CPLString(pszLCOList)
2515
0
                                 .ifind(CPLSPrintf("\"%s\"", pszKey)) !=
2516
0
                             std::string::npos ||
2517
0
                         CPLString(pszLCOList)
2518
0
                                 .ifind(CPLSPrintf("'%s'", pszKey)) !=
2519
0
                             std::string::npos))
2520
0
                    {
2521
0
                        pszAdditionalMsg = ", but a creation option of "
2522
0
                                           "that name exists.";
2523
0
                    }
2524
0
                }
2525
2526
0
                CPLError(CE_Warning, CPLE_NotSupported,
2527
0
                         "%s does not support %s %s%s",
2528
0
                         pszErrorMessageContainerName,
2529
0
                         pszErrorMessageOptionType, pszKey, pszAdditionalMsg);
2530
0
                bRet = false;
2531
0
            }
2532
2533
0
            CPLFree(pszKey);
2534
0
            ++papszOptionsToValidate;
2535
0
            continue;
2536
0
        }
2537
2538
0
#ifdef DEBUG
2539
0
        CPLXMLNode *psChildSubNode = psChildNode->psChild;
2540
0
        while (psChildSubNode)
2541
0
        {
2542
0
            if (psChildSubNode->eType == CXT_Attribute)
2543
0
            {
2544
0
                if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2545
0
                      EQUAL(psChildSubNode->pszValue, "alias") ||
2546
0
                      EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2547
0
                      EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2548
0
                      EQUAL(psChildSubNode->pszValue, "description") ||
2549
0
                      EQUAL(psChildSubNode->pszValue, "type") ||
2550
0
                      EQUAL(psChildSubNode->pszValue, "min") ||
2551
0
                      EQUAL(psChildSubNode->pszValue, "max") ||
2552
0
                      EQUAL(psChildSubNode->pszValue, "default") ||
2553
0
                      EQUAL(psChildSubNode->pszValue, "maxsize") ||
2554
0
                      EQUAL(psChildSubNode->pszValue, "required") ||
2555
0
                      EQUAL(psChildSubNode->pszValue, "scope")))
2556
0
                {
2557
                    /* Driver error */
2558
0
                    CPLError(CE_Warning, CPLE_NotSupported,
2559
0
                             "%s : unhandled attribute '%s' for %s %s.",
2560
0
                             pszErrorMessageContainerName,
2561
0
                             psChildSubNode->pszValue, pszKey,
2562
0
                             pszErrorMessageOptionType);
2563
0
                }
2564
0
            }
2565
0
            psChildSubNode = psChildSubNode->psNext;
2566
0
        }
2567
0
#endif
2568
2569
0
        const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2570
0
        const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2571
0
        const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2572
0
        if (pszType != nullptr)
2573
0
        {
2574
0
            if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2575
0
            {
2576
0
                const char *pszValueIter = pszValue;
2577
0
                while (*pszValueIter)
2578
0
                {
2579
0
                    if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2580
0
                          *pszValueIter == '+' || *pszValueIter == '-'))
2581
0
                    {
2582
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2583
0
                                 "'%s' is an unexpected value for %s %s of "
2584
0
                                 "type int.",
2585
0
                                 pszValue, pszKey, pszErrorMessageOptionType);
2586
0
                        bRet = false;
2587
0
                        break;
2588
0
                    }
2589
0
                    ++pszValueIter;
2590
0
                }
2591
0
                if (*pszValueIter == '\0')
2592
0
                {
2593
0
                    if (pszMin && atoi(pszValue) < atoi(pszMin))
2594
0
                    {
2595
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2596
0
                                 "'%s' is an unexpected value for %s %s that "
2597
0
                                 "should be >= %s.",
2598
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2599
0
                                 pszMin);
2600
0
                        bRet = false;
2601
0
                    }
2602
0
                    if (pszMax && atoi(pszValue) > atoi(pszMax))
2603
0
                    {
2604
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2605
0
                                 "'%s' is an unexpected value for %s %s that "
2606
0
                                 "should be <= %s.",
2607
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2608
0
                                 pszMax);
2609
0
                        bRet = false;
2610
0
                    }
2611
0
                }
2612
0
            }
2613
0
            else if (EQUAL(pszType, "UNSIGNED INT"))
2614
0
            {
2615
0
                const char *pszValueIter = pszValue;
2616
0
                while (*pszValueIter)
2617
0
                {
2618
0
                    if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2619
0
                          *pszValueIter == '+'))
2620
0
                    {
2621
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2622
0
                                 "'%s' is an unexpected value for %s %s of "
2623
0
                                 "type unsigned int.",
2624
0
                                 pszValue, pszKey, pszErrorMessageOptionType);
2625
0
                        bRet = false;
2626
0
                        break;
2627
0
                    }
2628
0
                    ++pszValueIter;
2629
0
                }
2630
0
                if (*pszValueIter == '\0')
2631
0
                {
2632
0
                    if (pszMin && atoi(pszValue) < atoi(pszMin))
2633
0
                    {
2634
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2635
0
                                 "'%s' is an unexpected value for %s %s that "
2636
0
                                 "should be >= %s.",
2637
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2638
0
                                 pszMin);
2639
0
                        bRet = false;
2640
0
                    }
2641
0
                    if (pszMax && atoi(pszValue) > atoi(pszMax))
2642
0
                    {
2643
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2644
0
                                 "'%s' is an unexpected value for %s %s that "
2645
0
                                 "should be <= %s.",
2646
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2647
0
                                 pszMax);
2648
0
                        bRet = false;
2649
0
                    }
2650
0
                }
2651
0
            }
2652
0
            else if (EQUAL(pszType, "FLOAT"))
2653
0
            {
2654
0
                char *endPtr = nullptr;
2655
0
                double dfVal = CPLStrtod(pszValue, &endPtr);
2656
0
                if (!(endPtr == nullptr || *endPtr == '\0'))
2657
0
                {
2658
0
                    CPLError(
2659
0
                        CE_Warning, CPLE_NotSupported,
2660
0
                        "'%s' is an unexpected value for %s %s of type float.",
2661
0
                        pszValue, pszKey, pszErrorMessageOptionType);
2662
0
                    bRet = false;
2663
0
                }
2664
0
                else
2665
0
                {
2666
0
                    if (pszMin && dfVal < CPLAtof(pszMin))
2667
0
                    {
2668
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2669
0
                                 "'%s' is an unexpected value for %s %s that "
2670
0
                                 "should be >= %s.",
2671
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2672
0
                                 pszMin);
2673
0
                        bRet = false;
2674
0
                    }
2675
0
                    if (pszMax && dfVal > CPLAtof(pszMax))
2676
0
                    {
2677
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2678
0
                                 "'%s' is an unexpected value for %s %s that "
2679
0
                                 "should be <= %s.",
2680
0
                                 pszValue, pszKey, pszErrorMessageOptionType,
2681
0
                                 pszMax);
2682
0
                        bRet = false;
2683
0
                    }
2684
0
                }
2685
0
            }
2686
0
            else if (EQUAL(pszType, "BOOLEAN"))
2687
0
            {
2688
0
                if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2689
0
                      EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2690
0
                      EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2691
0
                {
2692
0
                    CPLError(CE_Warning, CPLE_NotSupported,
2693
0
                             "'%s' is an unexpected value for %s %s of type "
2694
0
                             "boolean.",
2695
0
                             pszValue, pszKey, pszErrorMessageOptionType);
2696
0
                    bRet = false;
2697
0
                }
2698
0
            }
2699
0
            else if (EQUAL(pszType, "STRING-SELECT"))
2700
0
            {
2701
0
                bool bMatchFound = false;
2702
0
                bool bOtherValuesElementFound = false;
2703
0
                CPLXMLNode *psStringSelect = psChildNode->psChild;
2704
0
                while (psStringSelect)
2705
0
                {
2706
0
                    if (psStringSelect->eType == CXT_Element &&
2707
0
                        EQUAL(psStringSelect->pszValue, "Value"))
2708
0
                    {
2709
0
                        CPLXMLNode *psOptionNode = psStringSelect->psChild;
2710
0
                        while (psOptionNode)
2711
0
                        {
2712
0
                            if (psOptionNode->eType == CXT_Text &&
2713
0
                                EQUAL(psOptionNode->pszValue, pszValue))
2714
0
                            {
2715
0
                                bMatchFound = true;
2716
0
                                break;
2717
0
                            }
2718
0
                            if (psOptionNode->eType == CXT_Attribute &&
2719
0
                                (EQUAL(psOptionNode->pszValue, "alias") ||
2720
0
                                 EQUAL(psOptionNode->pszValue,
2721
0
                                       "deprecated_alias")) &&
2722
0
                                EQUAL(psOptionNode->psChild->pszValue,
2723
0
                                      pszValue))
2724
0
                            {
2725
0
                                bMatchFound = true;
2726
0
                                break;
2727
0
                            }
2728
0
                            psOptionNode = psOptionNode->psNext;
2729
0
                        }
2730
0
                        if (bMatchFound)
2731
0
                            break;
2732
0
                    }
2733
0
                    else if (psStringSelect->eType == CXT_Element &&
2734
0
                             EQUAL(psStringSelect->pszValue, "OtherValues"))
2735
0
                    {
2736
0
                        bOtherValuesElementFound = true;
2737
0
                    }
2738
0
                    psStringSelect = psStringSelect->psNext;
2739
0
                }
2740
0
                if (!bMatchFound && !bOtherValuesElementFound)
2741
0
                {
2742
0
                    CPLError(CE_Warning, CPLE_NotSupported,
2743
0
                             "'%s' is an unexpected value for %s %s of type "
2744
0
                             "string-select.",
2745
0
                             pszValue, pszKey, pszErrorMessageOptionType);
2746
0
                    bRet = false;
2747
0
                }
2748
0
            }
2749
0
            else if (EQUAL(pszType, "STRING"))
2750
0
            {
2751
0
                const char *pszMaxSize =
2752
0
                    CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2753
0
                if (pszMaxSize != nullptr)
2754
0
                {
2755
0
                    if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2756
0
                    {
2757
0
                        CPLError(CE_Warning, CPLE_NotSupported,
2758
0
                                 "'%s' is of size %d, whereas maximum size for "
2759
0
                                 "%s %s is %d.",
2760
0
                                 pszValue, static_cast<int>(strlen(pszValue)),
2761
0
                                 pszKey, pszErrorMessageOptionType,
2762
0
                                 atoi(pszMaxSize));
2763
0
                        bRet = false;
2764
0
                    }
2765
0
                }
2766
0
            }
2767
0
            else
2768
0
            {
2769
                /* Driver error */
2770
0
                CPLError(CE_Warning, CPLE_NotSupported,
2771
0
                         "%s : type '%s' for %s %s is not recognized.",
2772
0
                         pszErrorMessageContainerName, pszType, pszKey,
2773
0
                         pszErrorMessageOptionType);
2774
0
            }
2775
0
        }
2776
0
        else
2777
0
        {
2778
            /* Driver error */
2779
0
            CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2780
0
                     pszErrorMessageContainerName, pszKey,
2781
0
                     pszErrorMessageOptionType);
2782
0
        }
2783
0
        CPLFree(pszKey);
2784
0
        ++papszOptionsToValidate;
2785
0
    }
2786
2787
0
    CPLDestroyXMLNode(psNode);
2788
0
    return bRet ? TRUE : FALSE;
2789
0
}
2790
2791
/************************************************************************/
2792
/*                         GDALIdentifyDriver()                         */
2793
/************************************************************************/
2794
2795
/**
2796
 * \brief Identify the driver that can open a dataset.
2797
 *
2798
 * This function will try to identify the driver that can open the passed file
2799
 * name by invoking the Identify method of each registered GDALDriver in turn.
2800
 * The first driver that successfully identifies the file name will be returned.
2801
 * If all drivers fail then NULL is returned.
2802
 *
2803
 * In order to reduce the need for such searches to touch the operating system
2804
 * file system machinery, it is possible to give an optional list of files.
2805
 * This is the list of all files at the same level in the file system as the
2806
 * target file, including the target file. The filenames will not include any
2807
 * path components, and are essentially just the output of VSIReadDir() on the
2808
 * parent directory. If the target object does not have filesystem semantics
2809
 * then the file list should be NULL.
2810
 *
2811
 * @param pszFilename the name of the file to access.  In the case of
2812
 * exotic drivers this may not refer to a physical file, but instead contain
2813
 * information for the driver on how to access a dataset.
2814
 *
2815
 * @param papszFileList an array of strings, whose last element is the NULL
2816
 * pointer.  These strings are filenames that are auxiliary to the main
2817
 * filename. The passed value may be NULL.
2818
 *
2819
 * @return A GDALDriverH handle or NULL on failure.  For C++ applications
2820
 * this handle can be cast to a GDALDriver *.
2821
 */
2822
2823
GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2824
                                           CSLConstList papszFileList)
2825
2826
0
{
2827
0
    return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2828
0
}
2829
2830
/************************************************************************/
2831
/*                        GDALIdentifyDriverEx()                        */
2832
/************************************************************************/
2833
2834
/**
2835
 * \brief Identify the driver that can open a dataset.
2836
 *
2837
 * This function will try to identify the driver that can open the passed file
2838
 * name by invoking the Identify method of each registered GDALDriver in turn.
2839
 * The first driver that successfully identifies the file name will be returned.
2840
 * If all drivers fail then NULL is returned.
2841
 *
2842
 * In order to reduce the need for such searches to touch the operating system
2843
 * file system machinery, it is possible to give an optional list of files.
2844
 * This is the list of all files at the same level in the file system as the
2845
 * target file, including the target file. The filenames will not include any
2846
 * path components, and are essentially just the output of VSIReadDir() on the
2847
 * parent directory. If the target object does not have filesystem semantics
2848
 * then the file list should be NULL.
2849
 *
2850
 * @param pszFilename the name of the file to access.  In the case of
2851
 * exotic drivers this may not refer to a physical file, but instead contain
2852
 * information for the driver on how to access a dataset.
2853
 *
2854
 * @param nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2855
 * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2856
 * both kinds are implied.
2857
 *
2858
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2859
 * terminated list of strings with the driver short names that must be
2860
 * considered.
2861
 *
2862
 * @param papszFileList an array of strings, whose last element is the NULL
2863
 * pointer.  These strings are filenames that are auxiliary to the main
2864
 * filename. The passed value may be NULL.
2865
 *
2866
 * @return A GDALDriverH handle or NULL on failure.  For C++ applications
2867
 * this handle can be cast to a GDALDriver *.
2868
 */
2869
2870
GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2871
    const char *pszFilename, unsigned int nIdentifyFlags,
2872
    const char *const *papszAllowedDrivers, const char *const *papszFileList)
2873
0
{
2874
0
    GDALDriverManager *poDM = GetGDALDriverManager();
2875
0
    CPLAssert(nullptr != poDM);
2876
2877
    // If no driver kind is specified, assume all are to be probed.
2878
0
    if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2879
0
        nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2880
2881
0
    GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2882
0
    oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2883
2884
0
    CPLErrorStateBackuper oBackuper;
2885
0
    CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2886
2887
0
    const int nDriverCount = poDM->GetDriverCount();
2888
2889
    // First pass: only use drivers that have a pfnIdentify implementation.
2890
0
    std::vector<GDALDriver *> apoSecondPassDrivers;
2891
0
    for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2892
0
    {
2893
0
        GDALDriver *poDriver = poDM->GetDriver(iDriver);
2894
0
        if (papszAllowedDrivers != nullptr &&
2895
0
            CSLFindString(papszAllowedDrivers,
2896
0
                          GDALGetDriverShortName(poDriver)) == -1)
2897
0
        {
2898
0
            continue;
2899
0
        }
2900
2901
0
        VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2902
2903
0
        if (poDriver->pfnIdentify == nullptr &&
2904
0
            poDriver->pfnIdentifyEx == nullptr)
2905
0
        {
2906
0
            continue;
2907
0
        }
2908
2909
0
        if (papszAllowedDrivers != nullptr &&
2910
0
            CSLFindString(papszAllowedDrivers,
2911
0
                          GDALGetDriverShortName(poDriver)) == -1)
2912
0
            continue;
2913
0
        if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2914
0
            (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2915
0
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2916
0
            continue;
2917
0
        if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2918
0
            (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2919
0
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2920
0
            continue;
2921
2922
0
        if (poDriver->pfnIdentifyEx)
2923
0
        {
2924
0
            if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2925
0
                return poDriver;
2926
0
        }
2927
0
        else
2928
0
        {
2929
0
            const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2930
0
            if (nIdentifyRes > 0)
2931
0
                return poDriver;
2932
0
            if (nIdentifyRes < 0 &&
2933
0
                poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2934
0
            {
2935
                // Not loaded plugin
2936
0
                apoSecondPassDrivers.push_back(poDriver);
2937
0
            }
2938
0
        }
2939
0
    }
2940
2941
    // second pass: try loading plugin drivers
2942
0
    for (auto poDriver : apoSecondPassDrivers)
2943
0
    {
2944
        // Force plugin driver loading
2945
0
        poDriver->GetMetadata();
2946
0
        if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2947
0
            return poDriver;
2948
0
    }
2949
2950
    // third pass: slow method.
2951
0
    for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2952
0
    {
2953
0
        GDALDriver *poDriver = poDM->GetDriver(iDriver);
2954
0
        if (papszAllowedDrivers != nullptr &&
2955
0
            CSLFindString(papszAllowedDrivers,
2956
0
                          GDALGetDriverShortName(poDriver)) == -1)
2957
0
        {
2958
0
            continue;
2959
0
        }
2960
2961
0
        VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2962
2963
0
        if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2964
0
            (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2965
0
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2966
0
            continue;
2967
0
        if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2968
0
            (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2969
0
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2970
0
            continue;
2971
2972
0
        if (poDriver->pfnIdentifyEx != nullptr)
2973
0
        {
2974
0
            if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2975
0
                continue;
2976
0
        }
2977
0
        else if (poDriver->pfnIdentify != nullptr)
2978
0
        {
2979
0
            if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2980
0
                continue;
2981
0
        }
2982
2983
0
        GDALDataset *poDS;
2984
0
        if (poDriver->pfnOpen != nullptr)
2985
0
        {
2986
0
            poDS = poDriver->pfnOpen(&oOpenInfo);
2987
0
            if (poDS != nullptr)
2988
0
            {
2989
0
                delete poDS;
2990
0
                return GDALDriver::ToHandle(poDriver);
2991
0
            }
2992
2993
0
            if (CPLGetLastErrorType() != CE_None)
2994
0
                return nullptr;
2995
0
        }
2996
0
        else if (poDriver->pfnOpenWithDriverArg != nullptr)
2997
0
        {
2998
0
            poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2999
0
            if (poDS != nullptr)
3000
0
            {
3001
0
                delete poDS;
3002
0
                return GDALDriver::ToHandle(poDriver);
3003
0
            }
3004
3005
0
            if (CPLGetLastErrorType() != CE_None)
3006
0
                return nullptr;
3007
0
        }
3008
0
    }
3009
3010
0
    return nullptr;
3011
0
}
3012
3013
/************************************************************************/
3014
/*                          GetMetadataItem()                           */
3015
/************************************************************************/
3016
3017
const char *GDALDriver::GetMetadataItem(const char *pszName,
3018
                                        const char *pszDomain)
3019
0
{
3020
0
    if (pszDomain == nullptr || pszDomain[0] == '\0')
3021
0
    {
3022
0
        if (EQUAL(pszName, GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST))
3023
0
        {
3024
0
            const char *pszVal = GDALMajorObject::GetMetadataItem(pszName, "");
3025
0
            if (pszVal)
3026
0
                return pszVal;
3027
0
            if (GetMetadataItem(GDAL_DCAP_RASTER))
3028
0
            {
3029
0
                auto poDM = GetGDALDriverManager();
3030
0
                auto poGTiffDrv = poDM->GetDriverByName("GTiff");
3031
0
                if (poGTiffDrv)
3032
0
                {
3033
0
                    const char *pszXML =
3034
0
                        poGTiffDrv->GetMetadataItem(pszName, "");
3035
0
                    if (pszXML)
3036
0
                    {
3037
0
                        CPLString osXML(pszXML);
3038
0
                        osXML.replaceAll("<Value>INTERNAL</Value>", "");
3039
0
                        return CPLSPrintf("%s", osXML.c_str());
3040
0
                    }
3041
0
                }
3042
0
            }
3043
0
        }
3044
0
    }
3045
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
3046
0
}
3047
3048
/************************************************************************/
3049
/*                          SetMetadataItem()                           */
3050
/************************************************************************/
3051
3052
CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
3053
                                   const char *pszDomain)
3054
3055
0
{
3056
0
    if (pszDomain == nullptr || pszDomain[0] == '\0')
3057
0
    {
3058
        /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
3059
0
        if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
3060
0
            GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
3061
0
        {
3062
0
            GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
3063
0
        }
3064
        /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
3065
0
        else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
3066
0
                 strchr(pszValue, ' ') == nullptr &&
3067
0
                 GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
3068
0
                     nullptr)
3069
0
        {
3070
0
            GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
3071
0
        }
3072
0
    }
3073
0
    return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
3074
0
}
3075
3076
/************************************************************************/
3077
/*                        InstantiateAlgorithm()                        */
3078
/************************************************************************/
3079
3080
//! @cond Doxygen_Suppress
3081
3082
GDALAlgorithm *
3083
GDALDriver::InstantiateAlgorithm(const std::vector<std::string> &aosPath)
3084
0
{
3085
0
    pfnInstantiateAlgorithm = GetInstantiateAlgorithmCallback();
3086
0
    if (pfnInstantiateAlgorithm)
3087
0
        return pfnInstantiateAlgorithm(aosPath);
3088
0
    return nullptr;
3089
0
}
3090
3091
/************************************************************************/
3092
/*                          DeclareAlgorithm()                          */
3093
/************************************************************************/
3094
3095
void GDALDriver::DeclareAlgorithm(const std::vector<std::string> &aosPath)
3096
0
{
3097
0
    const std::string osDriverName = GetDescription();
3098
0
    auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
3099
3100
0
    if (!singleton.HasDeclaredSubAlgorithm({"driver"}))
3101
0
    {
3102
0
        singleton.DeclareAlgorithm(
3103
0
            {"driver"},
3104
0
            []() -> std::unique_ptr<GDALAlgorithm>
3105
0
            {
3106
0
                return std::make_unique<GDALContainerAlgorithm>(
3107
0
                    "driver", "Command for driver specific operations.");
3108
0
            });
3109
0
    }
3110
3111
0
    std::vector<std::string> path = {"driver",
3112
0
                                     CPLString(osDriverName).tolower()};
3113
0
    if (!singleton.HasDeclaredSubAlgorithm(path))
3114
0
    {
3115
0
        auto lambda = [osDriverName]() -> std::unique_ptr<GDALAlgorithm>
3116
0
        {
3117
0
            auto poDriver =
3118
0
                GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3119
0
            if (poDriver)
3120
0
            {
3121
0
                const char *pszHelpTopic =
3122
0
                    poDriver->GetMetadataItem(GDAL_DMD_HELPTOPIC);
3123
0
                return std::make_unique<GDALContainerAlgorithm>(
3124
0
                    CPLString(osDriverName).tolower(),
3125
0
                    std::string("Command for ")
3126
0
                        .append(osDriverName)
3127
0
                        .append(" driver specific operations."),
3128
0
                    pszHelpTopic ? std::string("/").append(pszHelpTopic)
3129
0
                                 : std::string());
3130
0
            }
3131
0
            return nullptr;
3132
0
        };
3133
0
        singleton.DeclareAlgorithm(path, std::move(lambda));
3134
0
    }
3135
3136
0
    path.insert(path.end(), aosPath.begin(), aosPath.end());
3137
3138
0
    auto lambda = [osDriverName, aosPath]() -> std::unique_ptr<GDALAlgorithm>
3139
0
    {
3140
0
        auto poDriver =
3141
0
            GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3142
0
        if (poDriver)
3143
0
            return std::unique_ptr<GDALAlgorithm>(
3144
0
                poDriver->InstantiateAlgorithm(aosPath));
3145
0
        return nullptr;
3146
0
    };
3147
3148
0
    singleton.DeclareAlgorithm(path, std::move(lambda));
3149
3150
0
    CPL_IGNORE_RET_VAL(osDriverName);
3151
0
}
3152
3153
//! @endcond
3154
3155
/************************************************************************/
3156
/*                     DoesDriverHandleExtension()                      */
3157
/************************************************************************/
3158
3159
static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
3160
0
{
3161
0
    bool bRet = false;
3162
0
    const char *pszDriverExtensions =
3163
0
        GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
3164
0
    if (pszDriverExtensions)
3165
0
    {
3166
0
        const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
3167
0
        const int nTokens = aosTokens.size();
3168
0
        for (int j = 0; j < nTokens; ++j)
3169
0
        {
3170
0
            if (EQUAL(pszExt, aosTokens[j]))
3171
0
            {
3172
0
                bRet = true;
3173
0
                break;
3174
0
            }
3175
0
        }
3176
0
    }
3177
0
    return bRet;
3178
0
}
3179
3180
/************************************************************************/
3181
/*                      IsOnlyExpectedGDBDrivers()                      */
3182
/************************************************************************/
3183
3184
static bool IsOnlyExpectedGDBDrivers(const CPLStringList &aosDriverNames)
3185
0
{
3186
0
    for (const char *pszDrvName : aosDriverNames)
3187
0
    {
3188
0
        if (!EQUAL(pszDrvName, "OpenFileGDB") &&
3189
0
            !EQUAL(pszDrvName, "FileGDB") && !EQUAL(pszDrvName, "GPSBabel"))
3190
0
        {
3191
0
            return false;
3192
0
        }
3193
0
    }
3194
0
    return true;
3195
0
}
3196
3197
/************************************************************************/
3198
/*                 GDALGetOutputDriversForDatasetName()                 */
3199
/************************************************************************/
3200
3201
/** Return a list of driver short names that are likely candidates for the
3202
 * provided output file name.
3203
 *
3204
 * @param pszDestDataset Output dataset name (might not exist).
3205
 * @param nDatasetTypeFlag GDAL_OF_RASTER, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER
3206
 *                         or a binary-or'ed combination of them
3207
 * @param bSingleMatch Whether a single match is desired, that is to say the
3208
 *                     returned list will contain at most one item, which will
3209
 *                     be the first driver in the order they are registered to
3210
 *                     match the output dataset name. Note that in this mode, if
3211
 *                     nDatasetTypeFlag==GDAL_OF_RASTER and pszDestDataset has
3212
 *                     no extension, GTiff will be selected.
3213
 * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
3214
 *                     true and there are more than 2 candidates.
3215
 * @return NULL terminated list of driver short names.
3216
 * To be freed with CSLDestroy()
3217
 * @since 3.9
3218
 */
3219
char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
3220
                                          int nDatasetTypeFlag,
3221
                                          bool bSingleMatch, bool bEmitWarning)
3222
0
{
3223
0
    CPLStringList aosDriverNames;
3224
0
    CPLStringList aosMissingDriverNames;
3225
3226
0
    std::string osExt = CPLGetExtensionSafe(pszDestDataset);
3227
0
    if (EQUAL(osExt.c_str(), "zip"))
3228
0
    {
3229
0
        const CPLString osLower(CPLString(pszDestDataset).tolower());
3230
0
        if (osLower.endsWith(".shp.zip"))
3231
0
        {
3232
0
            osExt = "shp.zip";
3233
0
        }
3234
0
        else if (osLower.endsWith(".gpkg.zip"))
3235
0
        {
3236
0
            osExt = "gpkg.zip";
3237
0
        }
3238
0
    }
3239
0
    else if (EQUAL(osExt.c_str(), "json"))
3240
0
    {
3241
0
        const CPLString osLower(CPLString(pszDestDataset).tolower());
3242
0
        if (osLower.endsWith(".gdalg.json"))
3243
0
            return nullptr;
3244
0
    }
3245
3246
0
    auto poDM = GetGDALDriverManager();
3247
0
    const int nDriverCount = poDM->GetDriverCount(true);
3248
0
    GDALDriver *poMissingPluginDriver = nullptr;
3249
0
    std::string osMatchingPrefix;
3250
0
    for (int i = 0; i < nDriverCount; i++)
3251
0
    {
3252
0
        GDALDriver *poDriver = poDM->GetDriver(i, true);
3253
0
        bool bOk = false;
3254
0
        if ((poDriver->GetMetadataItem(GDAL_DCAP_CREATE) != nullptr ||
3255
0
             poDriver->GetMetadataItem(GDAL_DCAP_CREATECOPY) != nullptr ||
3256
0
             poDriver->GetMetadataItem(GDAL_DCAP_UPDATE) != nullptr) &&
3257
0
            (((nDatasetTypeFlag & GDAL_OF_RASTER) &&
3258
0
              poDriver->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr) ||
3259
0
             ((nDatasetTypeFlag & GDAL_OF_VECTOR) &&
3260
0
              poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr) ||
3261
0
             ((nDatasetTypeFlag & GDAL_OF_MULTIDIM_RASTER) &&
3262
0
              poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) != nullptr)))
3263
0
        {
3264
0
            bOk = true;
3265
0
        }
3266
0
        else if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM) &&
3267
0
                 (nDatasetTypeFlag & GDAL_OF_VECTOR) != 0)
3268
0
        {
3269
0
            bOk = true;
3270
0
        }
3271
0
        if (bOk)
3272
0
        {
3273
0
            if (!osExt.empty() &&
3274
0
                DoesDriverHandleExtension(GDALDriver::ToHandle(poDriver),
3275
0
                                          osExt.c_str()))
3276
0
            {
3277
0
                if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3278
0
                {
3279
0
                    poMissingPluginDriver = poDriver;
3280
0
                    aosMissingDriverNames.AddString(poDriver->GetDescription());
3281
0
                }
3282
0
                else
3283
0
                    aosDriverNames.AddString(poDriver->GetDescription());
3284
0
            }
3285
0
            else
3286
0
            {
3287
0
                const char *pszPrefix =
3288
0
                    poDriver->GetMetadataItem(GDAL_DMD_CONNECTION_PREFIX);
3289
0
                if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
3290
0
                {
3291
0
                    if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3292
0
                    {
3293
0
                        osMatchingPrefix = pszPrefix;
3294
0
                        poMissingPluginDriver = poDriver;
3295
0
                        aosMissingDriverNames.AddString(
3296
0
                            poDriver->GetDescription());
3297
0
                    }
3298
0
                    else
3299
0
                        aosDriverNames.AddString(poDriver->GetDescription());
3300
0
                }
3301
0
            }
3302
0
        }
3303
0
    }
3304
3305
    // GMT is registered before netCDF for opening reasons, but we want
3306
    // netCDF to be used by default for output.
3307
0
    if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
3308
0
        EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
3309
0
    {
3310
0
        aosDriverNames.Clear();
3311
0
        aosDriverNames.AddString("netCDF");
3312
0
        aosDriverNames.AddString("GMT");
3313
0
    }
3314
3315
0
    if (bSingleMatch)
3316
0
    {
3317
0
        if (nDatasetTypeFlag == GDAL_OF_RASTER)
3318
0
        {
3319
0
            if (aosDriverNames.empty())
3320
0
            {
3321
0
                if (osExt.empty())
3322
0
                {
3323
0
                    aosDriverNames.AddString("GTiff");
3324
0
                }
3325
0
            }
3326
0
            else if (aosDriverNames.size() >= 2)
3327
0
            {
3328
0
                if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3329
0
                                      EQUAL(aosDriverNames[1], "COG")))
3330
0
                {
3331
0
                    CPLError(CE_Warning, CPLE_AppDefined,
3332
0
                             "Several drivers matching %s extension. Using %s",
3333
0
                             osExt.c_str(), aosDriverNames[0]);
3334
0
                }
3335
0
                const std::string osDrvName = aosDriverNames[0];
3336
0
                aosDriverNames.Clear();
3337
0
                aosDriverNames.AddString(osDrvName.c_str());
3338
0
            }
3339
0
        }
3340
0
        else if (EQUAL(osExt.c_str(), "gdb") &&
3341
0
                 IsOnlyExpectedGDBDrivers(aosDriverNames))
3342
0
        {
3343
            // Do not warn about that case given that FileGDB write support
3344
            // forwards to OpenFileGDB one. And also consider GPSBabel as too
3345
            // marginal to deserve the warning.
3346
0
            aosDriverNames.Clear();
3347
0
            aosDriverNames.AddString("OpenFileGDB");
3348
0
        }
3349
0
        else if (aosDriverNames.size() >= 2)
3350
0
        {
3351
0
            if (bEmitWarning)
3352
0
            {
3353
0
                CPLError(CE_Warning, CPLE_AppDefined,
3354
0
                         "Several drivers matching %s %s. Using %s",
3355
0
                         osMatchingPrefix.empty() ? osExt.c_str()
3356
0
                                                  : osMatchingPrefix.c_str(),
3357
0
                         osMatchingPrefix.empty() ? "extension" : "prefix",
3358
0
                         aosDriverNames[0]);
3359
0
            }
3360
0
            const std::string osDrvName = aosDriverNames[0];
3361
0
            aosDriverNames.Clear();
3362
0
            aosDriverNames.AddString(osDrvName.c_str());
3363
0
        }
3364
0
    }
3365
3366
0
    if (aosDriverNames.empty() && bEmitWarning &&
3367
0
        aosMissingDriverNames.size() == 1 && poMissingPluginDriver)
3368
0
    {
3369
0
        CPLError(CE_Failure, CPLE_AppDefined,
3370
0
                 "No installed driver matching %s %s, but %s driver is "
3371
0
                 "known. However plugin %s",
3372
0
                 osMatchingPrefix.empty() ? osExt.c_str()
3373
0
                                          : osMatchingPrefix.c_str(),
3374
0
                 osMatchingPrefix.empty() ? "extension" : "prefix",
3375
0
                 poMissingPluginDriver->GetDescription(),
3376
0
                 GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver)
3377
0
                     .c_str());
3378
0
    }
3379
0
    else if (aosDriverNames.empty() && bEmitWarning &&
3380
0
             aosMissingDriverNames.empty())
3381
0
    {
3382
0
        for (const auto &sConnectionPrefix : asKnownConnectionPrefixes)
3383
0
        {
3384
0
            if (STARTS_WITH_CI(pszDestDataset, sConnectionPrefix.pszPrefix))
3385
0
            {
3386
0
                CPLError(CE_Failure, CPLE_AppDefined,
3387
0
                         "Filename %s starts with the connection prefix of "
3388
0
                         "driver %s, which is not enabled in this GDAL build. "
3389
0
                         "If that filename is really intended, explicitly "
3390
0
                         "specify its output format.",
3391
0
                         pszDestDataset, sConnectionPrefix.pszDriverName);
3392
0
                break;
3393
0
            }
3394
0
        }
3395
0
    }
3396
3397
0
    return aosDriverNames.StealList();
3398
0
}
3399
3400
/************************************************************************/
3401
/*               GDALGetMessageAboutMissingPluginDriver()               */
3402
/************************************************************************/
3403
3404
std::string
3405
GDALGetMessageAboutMissingPluginDriver(GDALDriver *poMissingPluginDriver)
3406
0
{
3407
0
    std::string osMsg =
3408
0
        poMissingPluginDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME");
3409
0
    osMsg += " is not available in your "
3410
0
             "installation.";
3411
0
    if (const char *pszInstallationMsg = poMissingPluginDriver->GetMetadataItem(
3412
0
            GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
3413
0
    {
3414
0
        osMsg += " ";
3415
0
        osMsg += pszInstallationMsg;
3416
0
    }
3417
3418
0
    VSIStatBuf sStat;
3419
0
    if (const char *pszGDALDriverPath =
3420
0
            CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr))
3421
0
    {
3422
0
        if (VSIStat(pszGDALDriverPath, &sStat) != 0)
3423
0
        {
3424
0
            if (osMsg.back() != '.')
3425
0
                osMsg += ".";
3426
0
            osMsg += " Directory '";
3427
0
            osMsg += pszGDALDriverPath;
3428
0
            osMsg += "' pointed by GDAL_DRIVER_PATH does not exist.";
3429
0
        }
3430
0
    }
3431
0
    else
3432
0
    {
3433
0
        if (osMsg.back() != '.')
3434
0
            osMsg += ".";
3435
#ifdef INSTALL_PLUGIN_FULL_DIR
3436
        if (VSIStat(INSTALL_PLUGIN_FULL_DIR, &sStat) != 0)
3437
        {
3438
            osMsg += " Directory '";
3439
            osMsg += INSTALL_PLUGIN_FULL_DIR;
3440
            osMsg += "' hardcoded in the GDAL library does not "
3441
                     "exist and the GDAL_DRIVER_PATH "
3442
                     "configuration option is not set.";
3443
        }
3444
        else
3445
#endif
3446
0
        {
3447
0
            osMsg += " The GDAL_DRIVER_PATH configuration "
3448
0
                     "option is not set.";
3449
0
        }
3450
0
    }
3451
0
    return osMsg;
3452
0
}
3453
3454
/************************************************************************/
3455
/*                       GDALClearMemoryCaches()                        */
3456
/************************************************************************/
3457
3458
/**
3459
 * \brief Clear all GDAL-controlled in-memory caches.
3460
 *
3461
 * Iterates registered drivers and calls their pfnClearCaches callback if set,
3462
 * then calls VSICurlClearCache() to clear /vsicurl/ and related caches.
3463
 *
3464
 * Note that neither the global raster block cache or caches specific to open
3465
 * dataset objects are not cleared by this function (in its current implementation).
3466
 *
3467
 * Useful when remote datasets may have changed during the lifetime of a
3468
 * process.
3469
 *
3470
 * @since GDAL 3.13
3471
 */
3472
void GDALClearMemoryCaches()
3473
0
{
3474
0
    auto *poDM = GetGDALDriverManager();
3475
0
    if (poDM)
3476
0
    {
3477
0
        for (int i = 0; i < poDM->GetDriverCount(); i++)
3478
0
        {
3479
0
            auto *poDriver = poDM->GetDriver(i);
3480
0
            if (poDriver && poDriver->pfnClearCaches)
3481
0
                poDriver->pfnClearCaches(poDriver);
3482
0
        }
3483
0
    }
3484
0
    VSICurlClearCache();
3485
0
}