Coverage Report

Created: 2025-06-13 06:29

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