Coverage Report

Created: 2025-08-28 06:57

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