• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 13741725950

08 Mar 2025 09:43PM UTC coverage: 70.343% (-0.002%) from 70.345%
13741725950

Pull #11933

github

web-flow
Merge d1b82d9e2 into b047461f3
Pull Request #11933: Doc: Fix axis order of points in osr.CoordinateTransformation examples

552732 of 785762 relevant lines covered (70.34%)

221540.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.51
/gcore/gdaldriver.cpp
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

19
#include <cerrno>
20
#include <cstdlib>
21
#include <cstring>
22
#include <set>
23
#include <sys/stat.h>
24

25
#include "cpl_conv.h"
26
#include "cpl_error.h"
27
#include "cpl_minixml.h"
28
#include "cpl_progress.h"
29
#include "cpl_string.h"
30
#include "cpl_vsi.h"
31
#include "ograpispy.h"
32
#include "ogr_core.h"
33
#include "ogrsf_frmts.h"
34

35
/************************************************************************/
36
/*                             GDALDriver()                             */
37
/************************************************************************/
38

39
GDALDriver::GDALDriver() = default;
40

41
/************************************************************************/
42
/*                            ~GDALDriver()                             */
43
/************************************************************************/
44

45
GDALDriver::~GDALDriver()
356,912✔
46

47
{
48
    if (pfnUnloadDriver != nullptr)
202,451✔
49
        pfnUnloadDriver(this);
5,651✔
50
}
356,912✔
51

52
/************************************************************************/
53
/*                         GDALCreateDriver()                           */
54
/************************************************************************/
55

56
/**
57
 * \brief Create a GDALDriver.
58
 *
59
 * Creates a driver in the GDAL heap.
60
 */
61

62
GDALDriverH CPL_STDCALL GDALCreateDriver()
223✔
63
{
64
    return new GDALDriver();
223✔
65
}
66

67
/************************************************************************/
68
/*                         GDALDestroyDriver()                          */
69
/************************************************************************/
70

71
/**
72
 * \brief Destroy a GDALDriver.
73
 *
74
 * This is roughly equivalent to deleting the driver, but is guaranteed
75
 * to take place in the GDAL heap.  It is important this that function
76
 * not be called on a driver that is registered with the GDALDriverManager.
77
 *
78
 * @param hDriver the driver to destroy.
79
 */
80

81
void CPL_STDCALL GDALDestroyDriver(GDALDriverH hDriver)
×
82

83
{
84
    if (hDriver != nullptr)
×
85
        delete GDALDriver::FromHandle(hDriver);
×
86
}
×
87

88
/************************************************************************/
89
/*                               Open()                                 */
90
/************************************************************************/
91

92
//! @cond Doxygen_Suppress
93

94
GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
429,382✔
95
{
96

97
    GDALDataset *poDS = nullptr;
429,382✔
98
    pfnOpen = GetOpenCallback();
429,382✔
99
    if (pfnOpen != nullptr)
429,255✔
100
    {
101
        poDS = pfnOpen(poOpenInfo);
429,262✔
102
    }
103
    else if (pfnOpenWithDriverArg != nullptr)
×
104
    {
105
        poDS = pfnOpenWithDriverArg(this, poOpenInfo);
3✔
106
    }
107

108
    if (poDS)
429,560✔
109
    {
110
        // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
111
        // poDS->nOpenFlags
112
        int nOpenFlags = poOpenInfo->nOpenFlags &
49,644✔
113
                         ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
114
        if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
49,644✔
115
            nOpenFlags |= GDAL_OF_THREAD_SAFE;
905✔
116
        poDS->nOpenFlags = nOpenFlags;
49,644✔
117

118
        if (strlen(poDS->GetDescription()) == 0)
49,644✔
119
            poDS->SetDescription(poOpenInfo->pszFilename);
9,993✔
120

121
        if (poDS->poDriver == nullptr)
49,539✔
122
            poDS->poDriver = this;
46,738✔
123

124
        if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
49,539✔
125
        {
126
            poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
29✔
127
        }
128

129
        if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
49,539✔
130
        {
131
            if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
40,568✔
132
                CPLDebug(
6✔
133
                    "GDAL",
134
                    "GDALOpen(%s, this=%p) succeeds as "
135
                    "%s (pid=%d, responsiblePID=%d).",
136
                    poOpenInfo->pszFilename, poDS, GetDescription(),
6✔
137
                    static_cast<int>(CPLGetPID()),
6✔
138
                    static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
6✔
139
            else
140
                CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
40,576✔
141
                         poOpenInfo->pszFilename, poDS, GetDescription());
40,539✔
142

143
            poDS->AddToDatasetOpenList();
40,699✔
144
        }
145
    }
146

147
    return poDS;
429,564✔
148
}
149

150
//! @endcond
151

152
/************************************************************************/
153
/*                               Create()                               */
154
/************************************************************************/
155

156
/**
157
 * \brief Create a new dataset with this driver.
158
 *
159
 * What argument values are legal for particular drivers is driver specific,
160
 * and there is no way to query in advance to establish legal values.
161
 *
162
 * That function will try to validate the creation option list passed to the
163
 * driver with the GDALValidateCreationOptions() method. This check can be
164
 * disabled by defining the configuration option
165
 * GDAL_VALIDATE_CREATION_OPTIONS=NO.
166
 *
167
 * After you have finished working with the returned dataset, it is
168
 * <b>required</b> to close it with GDALClose(). This does not only close the
169
 * file handle, but also ensures that all the data and metadata has been written
170
 * to the dataset (GDALFlushCache() is not sufficient for that purpose).
171
 *
172
 * In GDAL 2, the arguments nXSize, nYSize and nBands can be passed to 0 when
173
 * creating a vector-only dataset for a compatible driver.
174
 *
175
 * Equivalent of the C function GDALCreate().
176
 *
177
 * @param pszFilename the name of the dataset to create.  UTF-8 encoded.
178
 * @param nXSize width of created raster in pixels.
179
 * @param nYSize height of created raster in pixels.
180
 * @param nBands number of bands.
181
 * @param eType type of raster.
182
 * @param papszOptions list of driver specific control parameters.
183
 * The APPEND_SUBDATASET=YES option can be
184
 * specified to avoid prior destruction of existing dataset.
185
 *
186
 * @return NULL on failure, or a new GDALDataset.
187
 */
188

189
GDALDataset *GDALDriver::Create(const char *pszFilename, int nXSize, int nYSize,
19,421✔
190
                                int nBands, GDALDataType eType,
191
                                CSLConstList papszOptions)
192

193
{
194
    /* -------------------------------------------------------------------- */
195
    /*      Does this format support creation.                              */
196
    /* -------------------------------------------------------------------- */
197
    pfnCreate = GetCreateCallback();
19,421✔
198
    if (CPL_UNLIKELY(pfnCreate == nullptr && pfnCreateEx == nullptr &&
19,421✔
199
                     pfnCreateVectorOnly == nullptr))
200
    {
201
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
202
                 "GDALDriver::Create() ... no create method implemented"
203
                 " for this format.");
204

205
        return nullptr;
1✔
206
    }
207
    /* -------------------------------------------------------------------- */
208
    /*      Do some rudimentary argument checking.                          */
209
    /* -------------------------------------------------------------------- */
210
    if (CPL_UNLIKELY(nBands < 0))
19,420✔
211
    {
212
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
213
                 "Attempt to create dataset with %d bands is illegal,"
214
                 "Must be >= 0.",
215
                 nBands);
216
        return nullptr;
1✔
217
    }
218

219
    if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
19,419✔
220
                     GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
221
                     (nXSize < 1 || nYSize < 1)))
19,419✔
222
    {
223
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
224
                 "Attempt to create %dx%d dataset is illegal,"
225
                 "sizes must be larger than zero.",
226
                 nXSize, nYSize);
227
        return nullptr;
1✔
228
    }
229

230
    if (CPL_UNLIKELY(nBands != 0 &&
19,418✔
231
                     (eType == GDT_Unknown || eType == GDT_TypeCount)))
232
    {
233
        CPLError(CE_Failure, CPLE_IllegalArg,
1✔
234
                 "Illegal GDT_Unknown/GDT_TypeCount argument");
235
        return nullptr;
1✔
236
    }
237

238
    /* -------------------------------------------------------------------- */
239
    /*      Make sure we cleanup if there is an existing dataset of this    */
240
    /*      name.  But even if that seems to fail we will continue since    */
241
    /*      it might just be a corrupt file or something.                   */
242
    /* -------------------------------------------------------------------- */
243
    if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
19,417✔
244
    {
245
        // Someone issuing Create("foo.tif") on a
246
        // memory driver doesn't expect files with those names to be deleted
247
        // on a file system...
248
        // This is somewhat messy. Ideally there should be a way for the
249
        // driver to overload the default behavior
250
        if (!EQUAL(GetDescription(), "MEM") &&
19,401✔
251
            !EQUAL(GetDescription(), "Memory") &&
29,710✔
252
            // ogr2ogr -f PostgreSQL might reach the Delete method of the
253
            // PostgisRaster driver which is undesirable
254
            !EQUAL(GetDescription(), "PostgreSQL"))
10,309✔
255
        {
256
            QuietDelete(pszFilename);
10,307✔
257
        }
258
    }
259

260
    /* -------------------------------------------------------------------- */
261
    /*      Validate creation options.                                      */
262
    /* -------------------------------------------------------------------- */
263
    if (CPLTestBool(
19,417✔
264
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
265
        GDALValidateCreationOptions(this, papszOptions);
19,417✔
266

267
    /* -------------------------------------------------------------------- */
268
    /*      Proceed with creation.                                          */
269
    /* -------------------------------------------------------------------- */
270
    CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
38,834✔
271
             GetDescription(), pszFilename, nXSize, nYSize, nBands,
19,417✔
272
             GDALGetDataTypeName(eType), papszOptions);
273

274
    GDALDataset *poDS = nullptr;
19,417✔
275
    if (pfnCreateEx != nullptr)
19,417✔
276
    {
277
        poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
×
278
                           const_cast<char **>(papszOptions));
279
    }
280
    else if (pfnCreate != nullptr)
19,417✔
281
    {
282
        poDS = pfnCreate(pszFilename, nXSize, nYSize, nBands, eType,
19,417✔
283
                         const_cast<char **>(papszOptions));
284
    }
285
    else if (nBands < 1)
×
286
    {
287
        poDS = pfnCreateVectorOnly(this, pszFilename,
×
288
                                   const_cast<char **>(papszOptions));
289
    }
290

291
    if (poDS != nullptr)
19,416✔
292
    {
293
        if (poDS->GetDescription() == nullptr ||
36,407✔
294
            strlen(poDS->GetDescription()) == 0)
18,204✔
295
            poDS->SetDescription(pszFilename);
15,430✔
296

297
        if (poDS->poDriver == nullptr)
18,202✔
298
            poDS->poDriver = this;
17,580✔
299

300
        poDS->AddToDatasetOpenList();
18,202✔
301
    }
302

303
    return poDS;
19,417✔
304
}
305

306
/************************************************************************/
307
/*                             GDALCreate()                             */
308
/************************************************************************/
309

310
/**
311
 * \brief Create a new dataset with this driver.
312
 *
313
 * @see GDALDriver::Create()
314
 */
315

316
GDALDatasetH CPL_DLL CPL_STDCALL GDALCreate(GDALDriverH hDriver,
15,339✔
317
                                            const char *pszFilename, int nXSize,
318
                                            int nYSize, int nBands,
319
                                            GDALDataType eBandType,
320
                                            CSLConstList papszOptions)
321

322
{
323
    VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
15,339✔
324

325
    GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
15,339✔
326
        pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
327

328
#ifdef OGRAPISPY_ENABLED
329
    if (nBands < 1)
15,339✔
330
    {
331
        OGRAPISpyCreateDataSource(hDriver, pszFilename,
2,953✔
332
                                  const_cast<char **>(papszOptions), hDS);
333
    }
334
#endif
335

336
    return hDS;
15,339✔
337
}
338

339
/************************************************************************/
340
/*                       CreateMultiDimensional()                       */
341
/************************************************************************/
342

343
/**
344
 * \brief Create a new multidimensional dataset with this driver.
345
 *
346
 * Only drivers that advertise the GDAL_DCAP_MULTIDIM_RASTER capability and
347
 * implement the pfnCreateMultiDimensional method might return a non nullptr
348
 * GDALDataset.
349
 *
350
 * This is the same as the C function GDALCreateMultiDimensional().
351
 *
352
 * @param pszFilename  the name of the dataset to create.  UTF-8 encoded.
353
 * @param papszRootGroupOptions driver specific options regarding the creation
354
 *                              of the root group. Might be nullptr.
355
 * @param papszOptions driver specific options regarding the creation
356
 *                     of the dataset. Might be nullptr.
357
 * @return a new dataset, or nullptr in case of failure.
358
 *
359
 * @since GDAL 3.1
360
 */
361

362
GDALDataset *
363
GDALDriver::CreateMultiDimensional(const char *pszFilename,
467✔
364
                                   CSLConstList papszRootGroupOptions,
365
                                   CSLConstList papszOptions)
366

367
{
368
    /* -------------------------------------------------------------------- */
369
    /*      Does this format support creation.                              */
370
    /* -------------------------------------------------------------------- */
371
    pfnCreateMultiDimensional = GetCreateMultiDimensionalCallback();
467✔
372
    if (pfnCreateMultiDimensional == nullptr)
467✔
373
    {
374
        CPLError(CE_Failure, CPLE_NotSupported,
×
375
                 "GDALDriver::CreateMultiDimensional() ... "
376
                 "no CreateMultiDimensional method implemented "
377
                 "for this format.");
378

379
        return nullptr;
×
380
    }
381

382
    /* -------------------------------------------------------------------- */
383
    /*      Validate creation options.                                      */
384
    /* -------------------------------------------------------------------- */
385
    if (CPLTestBool(
467✔
386
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
387
    {
388
        const char *pszOptionList =
389
            GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
467✔
390
        CPLString osDriver;
934✔
391
        osDriver.Printf("driver %s", GetDescription());
467✔
392
        GDALValidateOptions(pszOptionList, papszOptions, "creation option",
467✔
393
                            osDriver);
394
    }
395

396
    auto poDstDS = pfnCreateMultiDimensional(pszFilename, papszRootGroupOptions,
467✔
397
                                             papszOptions);
398

399
    if (poDstDS != nullptr)
467✔
400
    {
401
        if (poDstDS->GetDescription() == nullptr ||
930✔
402
            strlen(poDstDS->GetDescription()) == 0)
465✔
403
            poDstDS->SetDescription(pszFilename);
94✔
404

405
        if (poDstDS->poDriver == nullptr)
465✔
406
            poDstDS->poDriver = this;
463✔
407
    }
408

409
    return poDstDS;
467✔
410
}
411

412
/************************************************************************/
413
/*                       GDALCreateMultiDimensional()                   */
414
/************************************************************************/
415

416
/** \brief Create a new multidimensional dataset with this driver.
417
 *
418
 * This is the same as the C++ method GDALDriver::CreateMultiDimensional().
419
 */
420
GDALDatasetH GDALCreateMultiDimensional(GDALDriverH hDriver,
422✔
421
                                        const char *pszName,
422
                                        CSLConstList papszRootGroupOptions,
423
                                        CSLConstList papszOptions)
424
{
425
    VALIDATE_POINTER1(hDriver, __func__, nullptr);
422✔
426
    VALIDATE_POINTER1(pszName, __func__, nullptr);
422✔
427
    return GDALDataset::ToHandle(
422✔
428
        GDALDriver::FromHandle(hDriver)->CreateMultiDimensional(
429
            pszName, papszRootGroupOptions, papszOptions));
422✔
430
}
431

432
/************************************************************************/
433
/*                  DefaultCreateCopyMultiDimensional()                 */
434
/************************************************************************/
435

436
//! @cond Doxygen_Suppress
437

438
CPLErr GDALDriver::DefaultCreateCopyMultiDimensional(
18✔
439
    GDALDataset *poSrcDS, GDALDataset *poDstDS, bool bStrict,
440
    CSLConstList papszOptions, GDALProgressFunc pfnProgress,
441
    void *pProgressData)
442
{
443
    if (pfnProgress == nullptr)
18✔
444
        pfnProgress = GDALDummyProgress;
2✔
445

446
    auto poSrcRG = poSrcDS->GetRootGroup();
36✔
447
    if (!poSrcRG)
18✔
448
        return CE_Failure;
×
449
    auto poDstRG = poDstDS->GetRootGroup();
36✔
450
    if (!poDstRG)
18✔
451
        return CE_Failure;
×
452
    GUInt64 nCurCost = 0;
18✔
453
    return poDstRG->CopyFrom(poDstRG, poSrcDS, poSrcRG, bStrict, nCurCost,
36✔
454
                             poSrcRG->GetTotalCopyCost(), pfnProgress,
455
                             pProgressData, papszOptions)
18✔
456
               ? CE_None
18✔
457
               : CE_Failure;
18✔
458
}
459

460
//! @endcond
461

462
/************************************************************************/
463
/*                          DefaultCopyMasks()                          */
464
/************************************************************************/
465

466
//! @cond Doxygen_Suppress
467
CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
5,855✔
468
                                    int bStrict)
469

470
{
471
    return DefaultCopyMasks(poSrcDS, poDstDS, bStrict, nullptr, nullptr,
5,855✔
472
                            nullptr);
5,855✔
473
}
474

475
CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
7,690✔
476
                                    int bStrict, CSLConstList /*papszOptions*/,
477
                                    GDALProgressFunc pfnProgress,
478
                                    void *pProgressData)
479

480
{
481
    if (pfnProgress == nullptr)
7,690✔
482
        pfnProgress = GDALDummyProgress;
5,855✔
483

484
    int nBands = poSrcDS->GetRasterCount();
7,690✔
485
    if (nBands == 0)
7,690✔
486
        return CE_None;
×
487

488
    /* -------------------------------------------------------------------- */
489
    /*      Try to copy mask if it seems appropriate.                       */
490
    /* -------------------------------------------------------------------- */
491
    const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
7,690✔
492
    CPLErr eErr = CE_None;
7,690✔
493

494
    int nTotalBandsWithMask = 0;
7,690✔
495
    for (int iBand = 0; iBand < nBands; ++iBand)
27,206✔
496
    {
497
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
19,516✔
498

499
        int nMaskFlags = poSrcBand->GetMaskFlags();
19,516✔
500
        if (!(nMaskFlags &
19,516✔
501
              (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
502
        {
503
            nTotalBandsWithMask++;
7✔
504
        }
505
    }
506

507
    int iBandWithMask = 0;
7,690✔
508
    for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
27,206✔
509
    {
510
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
19,516✔
511

512
        int nMaskFlags = poSrcBand->GetMaskFlags();
19,516✔
513
        if (eErr == CE_None && !(nMaskFlags & (GMF_ALL_VALID | GMF_PER_DATASET |
19,516✔
514
                                               GMF_ALPHA | GMF_NODATA)))
515
        {
516
            GDALRasterBand *poDstBand = poDstDS->GetRasterBand(iBand + 1);
7✔
517
            if (poDstBand != nullptr)
7✔
518
            {
519
                eErr = poDstBand->CreateMaskBand(nMaskFlags);
7✔
520
                if (eErr == CE_None)
7✔
521
                {
522
                    // coverity[divide_by_zero]
523
                    void *pScaledData = GDALCreateScaledProgress(
14✔
524
                        double(iBandWithMask) / nTotalBandsWithMask,
7✔
525
                        double(iBandWithMask + 1) / nTotalBandsWithMask,
7✔
526
                        pfnProgress, pProgressData);
527
                    eErr = GDALRasterBandCopyWholeRaster(
14✔
528
                        poSrcBand->GetMaskBand(), poDstBand->GetMaskBand(),
7✔
529
                        papszOptions, GDALScaledProgress, pScaledData);
530
                    GDALDestroyScaledProgress(pScaledData);
7✔
531
                }
532
                else if (!bStrict)
×
533
                {
534
                    eErr = CE_None;
×
535
                }
536
            }
537
        }
538
    }
539

540
    /* -------------------------------------------------------------------- */
541
    /*      Try to copy a per-dataset mask if we have one.                  */
542
    /* -------------------------------------------------------------------- */
543
    const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
7,690✔
544
    if (eErr == CE_None &&
7,690✔
545
        !(nMaskFlags & (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) &&
7,690✔
546
        (nMaskFlags & GMF_PER_DATASET))
11✔
547
    {
548
        eErr = poDstDS->CreateMaskBand(nMaskFlags);
7✔
549
        if (eErr == CE_None)
7✔
550
        {
551
            eErr = GDALRasterBandCopyWholeRaster(
7✔
552
                poSrcDS->GetRasterBand(1)->GetMaskBand(),
7✔
553
                poDstDS->GetRasterBand(1)->GetMaskBand(), papszOptions,
7✔
554
                pfnProgress, pProgressData);
555
        }
556
        else if (!bStrict)
×
557
        {
558
            eErr = CE_None;
×
559
        }
560
    }
561

562
    return eErr;
7,690✔
563
}
564

565
/************************************************************************/
566
/*                         DefaultCreateCopy()                          */
567
/************************************************************************/
568

569
GDALDataset *GDALDriver::DefaultCreateCopy(const char *pszFilename,
1,136✔
570
                                           GDALDataset *poSrcDS, int bStrict,
571
                                           CSLConstList papszOptions,
572
                                           GDALProgressFunc pfnProgress,
573
                                           void *pProgressData)
574

575
{
576
    if (pfnProgress == nullptr)
1,136✔
577
        pfnProgress = GDALDummyProgress;
×
578

579
    CPLErrorReset();
1,136✔
580

581
    /* -------------------------------------------------------------------- */
582
    /*      Use multidimensional raster API if available.                   */
583
    /* -------------------------------------------------------------------- */
584
    auto poSrcGroup = poSrcDS->GetRootGroup();
2,272✔
585
    if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
1,136✔
586
    {
587
        CPLStringList aosDatasetCO;
32✔
588
        for (const char *pszOption : cpl::Iterate(papszOptions))
23✔
589
        {
590
            if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
7✔
591
                aosDatasetCO.AddString(pszOption);
×
592
        }
593
        auto poDstDS = std::unique_ptr<GDALDataset>(
594
            CreateMultiDimensional(pszFilename, nullptr, aosDatasetCO.List()));
32✔
595
        if (!poDstDS)
16✔
596
            return nullptr;
×
597
        auto poDstGroup = poDstDS->GetRootGroup();
32✔
598
        if (!poDstGroup)
16✔
599
            return nullptr;
×
600
        if (DefaultCreateCopyMultiDimensional(
16✔
601
                poSrcDS, poDstDS.get(), CPL_TO_BOOL(bStrict), papszOptions,
16✔
602
                pfnProgress, pProgressData) != CE_None)
16✔
603
            return nullptr;
×
604
        return poDstDS.release();
16✔
605
    }
606

607
    /* -------------------------------------------------------------------- */
608
    /*      Validate that we can create the output as requested.            */
609
    /* -------------------------------------------------------------------- */
610
    const int nXSize = poSrcDS->GetRasterXSize();
1,120✔
611
    const int nYSize = poSrcDS->GetRasterYSize();
1,120✔
612
    const int nBands = poSrcDS->GetRasterCount();
1,120✔
613

614
    CPLDebug("GDAL", "Using default GDALDriver::CreateCopy implementation.");
1,120✔
615

616
    const int nLayerCount = poSrcDS->GetLayerCount();
1,120✔
617
    if (nBands == 0 && nLayerCount == 0 &&
1,143✔
618
        GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
23✔
619
    {
620
        CPLError(CE_Failure, CPLE_NotSupported,
17✔
621
                 "GDALDriver::DefaultCreateCopy does not support zero band");
622
        return nullptr;
17✔
623
    }
624
    if (poSrcDS->GetDriver() != nullptr &&
1,103✔
625
        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
1,102✔
626
        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
1,095✔
627
        GetMetadataItem(GDAL_DCAP_RASTER) == nullptr &&
2,208✔
628
        GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr)
3✔
629
    {
630
        CPLError(CE_Failure, CPLE_NotSupported,
3✔
631
                 "Source driver is raster-only whereas output driver is "
632
                 "vector-only");
633
        return nullptr;
3✔
634
    }
635
    else if (poSrcDS->GetDriver() != nullptr &&
1,100✔
636
             poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) ==
1,099✔
637
                 nullptr &&
7✔
638
             poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) !=
7✔
639
                 nullptr &&
7✔
640
             GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
2,199✔
641
             GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
×
642
    {
643
        CPLError(CE_Failure, CPLE_NotSupported,
×
644
                 "Source driver is vector-only whereas output driver is "
645
                 "raster-only");
646
        return nullptr;
×
647
    }
648

649
    if (!pfnProgress(0.0, nullptr, pProgressData))
1,100✔
650
    {
651
        CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2✔
652
        return nullptr;
2✔
653
    }
654

655
    /* -------------------------------------------------------------------- */
656
    /*      Propagate some specific structural metadata as options if it    */
657
    /*      appears to be supported by the target driver and the caller     */
658
    /*      didn't provide values.                                          */
659
    /* -------------------------------------------------------------------- */
660
    char **papszCreateOptions = CSLDuplicate(papszOptions);
1,098✔
661
    const char *const apszOptItems[] = {"NBITS", "IMAGE_STRUCTURE", "PIXELTYPE",
1,098✔
662
                                        "IMAGE_STRUCTURE", nullptr};
663

664
    for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
3,264✔
665
         iOptItem += 2)
2,166✔
666
    {
667
        // does the source have this metadata item on the first band?
668
        auto poBand = poSrcDS->GetRasterBand(1);
2,166✔
669
        poBand->EnablePixelTypeSignedByteWarning(false);
2,166✔
670
        const char *pszValue = poBand->GetMetadataItem(
4,332✔
671
            apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
2,166✔
672
        poBand->EnablePixelTypeSignedByteWarning(true);
2,166✔
673

674
        if (pszValue == nullptr)
2,166✔
675
            continue;
2,165✔
676

677
        // Do not override provided value.
678
        if (CSLFetchNameValue(papszCreateOptions, pszValue) != nullptr)
1✔
679
            continue;
×
680

681
        // Does this appear to be a supported creation option on this driver?
682
        const char *pszOptionList =
683
            GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1✔
684

685
        if (pszOptionList == nullptr ||
1✔
686
            strstr(pszOptionList, apszOptItems[iOptItem]) == nullptr)
1✔
687
            continue;
×
688

689
        papszCreateOptions = CSLSetNameValue(papszCreateOptions,
1✔
690
                                             apszOptItems[iOptItem], pszValue);
1✔
691
    }
692

693
    /* -------------------------------------------------------------------- */
694
    /*      Create destination dataset.                                     */
695
    /* -------------------------------------------------------------------- */
696
    GDALDataType eType = GDT_Unknown;
1,098✔
697

698
    if (nBands > 0)
1,098✔
699
        eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
1,083✔
700
    GDALDataset *poDstDS =
701
        Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
1,098✔
702

703
    CSLDestroy(papszCreateOptions);
1,098✔
704

705
    if (poDstDS == nullptr)
1,098✔
706
        return nullptr;
299✔
707

708
    int nDstBands = poDstDS->GetRasterCount();
799✔
709
    CPLErr eErr = CE_None;
799✔
710
    if (nDstBands != nBands)
799✔
711
    {
712
        if (GetMetadataItem(GDAL_DCAP_RASTER) != nullptr)
×
713
        {
714
            // Should not happen for a well-behaved driver.
715
            CPLError(
×
716
                CE_Failure, CPLE_AppDefined,
717
                "Output driver created only %d bands whereas %d were expected",
718
                nDstBands, nBands);
719
            eErr = CE_Failure;
×
720
        }
721
        nDstBands = 0;
×
722
    }
723

724
    /* -------------------------------------------------------------------- */
725
    /*      Try setting the projection and geotransform if it seems         */
726
    /*      suitable.                                                       */
727
    /* -------------------------------------------------------------------- */
728
    double adfGeoTransform[6] = {};
799✔
729

730
    if (nDstBands == 0 && !bStrict)
799✔
731
        CPLTurnFailureIntoWarning(true);
4✔
732

733
    if (eErr == CE_None &&
1,598✔
734
        poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None
799✔
735
        // TODO(schwehr): The default value check should be a function.
736
        && (adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0 ||
1,600✔
737
            adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0 ||
2✔
738
            adfGeoTransform[4] != 0.0 || adfGeoTransform[5] != 1.0))
2✔
739
    {
740
        eErr = poDstDS->SetGeoTransform(adfGeoTransform);
722✔
741
        if (!bStrict)
722✔
742
            eErr = CE_None;
378✔
743
    }
744

745
    if (eErr == CE_None)
799✔
746
    {
747
        const auto poSrcSRS = poSrcDS->GetSpatialRef();
790✔
748
        if (poSrcSRS && !poSrcSRS->IsEmpty())
790✔
749
        {
750
            eErr = poDstDS->SetSpatialRef(poSrcSRS);
670✔
751
            if (!bStrict)
670✔
752
                eErr = CE_None;
358✔
753
        }
754
    }
755

756
    /* -------------------------------------------------------------------- */
757
    /*      Copy GCPs.                                                      */
758
    /* -------------------------------------------------------------------- */
759
    if (poSrcDS->GetGCPCount() > 0 && eErr == CE_None)
799✔
760
    {
761
        eErr = poDstDS->SetGCPs(poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(),
2✔
762
                                poSrcDS->GetGCPProjection());
763
        if (!bStrict)
2✔
764
            eErr = CE_None;
1✔
765
    }
766

767
    if (nDstBands == 0 && !bStrict)
799✔
768
        CPLTurnFailureIntoWarning(false);
4✔
769

770
    /* -------------------------------------------------------------------- */
771
    /*      Copy metadata.                                                  */
772
    /* -------------------------------------------------------------------- */
773
    DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
799✔
774

775
    /* -------------------------------------------------------------------- */
776
    /*      Loop copying bands.                                             */
777
    /* -------------------------------------------------------------------- */
778
    for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
2,089✔
779
    {
780
        GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
1,290✔
781
        GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
1,290✔
782

783
        /* --------------------------------------------------------------------
784
         */
785
        /*      Do we need to copy a colortable. */
786
        /* --------------------------------------------------------------------
787
         */
788
        GDALColorTable *const poCT = poSrcBand->GetColorTable();
1,290✔
789
        if (poCT != nullptr)
1,290✔
790
            poDstBand->SetColorTable(poCT);
24✔
791

792
        /* --------------------------------------------------------------------
793
         */
794
        /*      Do we need to copy other metadata?  Most of this is */
795
        /*      non-critical, so lets not bother folks if it fails are we */
796
        /*      are not in strict mode. */
797
        /* --------------------------------------------------------------------
798
         */
799
        if (!bStrict)
1,290✔
800
            CPLTurnFailureIntoWarning(true);
679✔
801

802
        if (strlen(poSrcBand->GetDescription()) > 0)
1,290✔
803
            poDstBand->SetDescription(poSrcBand->GetDescription());
52✔
804

805
        if (CSLCount(poSrcBand->GetMetadata()) > 0)
1,290✔
806
            poDstBand->SetMetadata(poSrcBand->GetMetadata());
112✔
807

808
        int bSuccess = FALSE;
1,290✔
809
        double dfValue = poSrcBand->GetOffset(&bSuccess);
1,290✔
810
        if (bSuccess && dfValue != 0.0)
1,290✔
811
            poDstBand->SetOffset(dfValue);
5✔
812

813
        dfValue = poSrcBand->GetScale(&bSuccess);
1,290✔
814
        if (bSuccess && dfValue != 1.0)
1,290✔
815
            poDstBand->SetScale(dfValue);
4✔
816

817
        GDALCopyNoDataValue(poDstBand, poSrcBand);
1,290✔
818

819
        if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
2,120✔
820
            poSrcBand->GetColorInterpretation() !=
830✔
821
                poDstBand->GetColorInterpretation())
830✔
822
            poDstBand->SetColorInterpretation(
620✔
823
                poSrcBand->GetColorInterpretation());
620✔
824

825
        char **papszCatNames = poSrcBand->GetCategoryNames();
1,290✔
826
        if (nullptr != papszCatNames)
1,290✔
827
            poDstBand->SetCategoryNames(papszCatNames);
1✔
828

829
        // Only copy RAT if it is of reasonable size to fit in memory
830
        GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
1,290✔
831
        if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
1,292✔
832
                                        poRAT->GetRowCount() <
2✔
833
                                    1024 * 1024)
834
        {
835
            poDstBand->SetDefaultRAT(poRAT);
2✔
836
        }
837

838
        if (!bStrict)
1,290✔
839
        {
840
            CPLTurnFailureIntoWarning(false);
679✔
841
        }
842
        else
843
        {
844
            eErr = CPLGetLastErrorType();
611✔
845
        }
846
    }
847

848
    /* -------------------------------------------------------------------- */
849
    /*      Copy image data.                                                */
850
    /* -------------------------------------------------------------------- */
851
    if (eErr == CE_None && nDstBands > 0)
799✔
852
    {
853
        const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
755✔
854
                                                              nullptr};
855
        const bool bSkipHoles = CPLTestBool(
755✔
856
            CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
857
        eErr = GDALDatasetCopyWholeRaster(
755✔
858
            poSrcDS, poDstDS,
859
            bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
860
            pProgressData);
861
    }
862

863
    /* -------------------------------------------------------------------- */
864
    /*      Should we copy some masks over?                                 */
865
    /* -------------------------------------------------------------------- */
866
    if (eErr == CE_None && nDstBands > 0)
799✔
867
        eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
738✔
868

869
    /* -------------------------------------------------------------------- */
870
    /*      Copy vector layers                                              */
871
    /* -------------------------------------------------------------------- */
872
    if (eErr == CE_None)
799✔
873
    {
874
        if (nLayerCount > 0 && poDstDS->TestCapability(ODsCCreateLayer))
750✔
875
        {
876
            for (int iLayer = 0; iLayer < nLayerCount; ++iLayer)
20✔
877
            {
878
                OGRLayer *poLayer = poSrcDS->GetLayer(iLayer);
10✔
879

880
                if (poLayer == nullptr)
10✔
881
                    continue;
×
882

883
                poDstDS->CopyLayer(poLayer, poLayer->GetName(), nullptr);
10✔
884
            }
885
        }
886
    }
887

888
    /* -------------------------------------------------------------------- */
889
    /*      Try to cleanup the output dataset if the translation failed.    */
890
    /* -------------------------------------------------------------------- */
891
    if (eErr != CE_None)
799✔
892
    {
893
        delete poDstDS;
49✔
894
        if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
49✔
895
        {
896
            // Only delete if creating a new file
897
            Delete(pszFilename);
49✔
898
        }
899
        return nullptr;
49✔
900
    }
901
    else
902
    {
903
        CPLErrorReset();
750✔
904
    }
905

906
    return poDstDS;
750✔
907
}
908

909
/************************************************************************/
910
/*                       DefaultCopyMetadata()                          */
911
/************************************************************************/
912

913
void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
5,138✔
914
                                     CSLConstList papszOptions,
915
                                     CSLConstList papszExcludedDomains)
916
{
917
    const char *pszCopySrcMDD =
918
        CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
5,138✔
919
    char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
5,138✔
920
    if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
5,138✔
921
        papszSrcMDD)
922
    {
923
        if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
4✔
924
             CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
2✔
925
            CSLFindString(papszExcludedDomains, "") < 0 &&
10,119✔
926
            CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
4,979✔
927
        {
928
            if (poSrcDS->GetMetadata() != nullptr)
4,979✔
929
                poDstDS->SetMetadata(poSrcDS->GetMetadata());
680✔
930
        }
931

932
        /* -------------------------------------------------------------------- */
933
        /*      Copy transportable special domain metadata.                     */
934
        /*      It would be nice to copy geolocation, but it is pretty fragile. */
935
        /* -------------------------------------------------------------------- */
936
        constexpr const char *apszDefaultDomains[] = {
5,136✔
937
            "RPC", "xml:XMP", "json:ISIS3", "json:VICAR"};
938
        for (const char *pszDomain : apszDefaultDomains)
25,680✔
939
        {
940
            if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
41,072✔
941
                CSLFindString(papszExcludedDomains, pszDomain) < 0)
20,528✔
942
            {
943
                char **papszMD = poSrcDS->GetMetadata(pszDomain);
20,528✔
944
                if (papszMD)
20,528✔
945
                    poDstDS->SetMetadata(papszMD, pszDomain);
5✔
946
            }
947
        }
948

949
        if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
5,136✔
950
            papszSrcMDD)
951
        {
952
            for (const char *pszDomain :
24✔
953
                 CPLStringList(poSrcDS->GetMetadataDomainList()))
30✔
954
            {
955
                if (pszDomain[0] != 0 &&
36✔
956
                    (!papszSrcMDD ||
12✔
957
                     CSLFindString(papszSrcMDD, pszDomain) >= 0))
12✔
958
                {
959
                    bool bCanCopy = true;
10✔
960
                    if (CSLFindString(papszExcludedDomains, pszDomain) >= 0)
10✔
961
                    {
962
                        bCanCopy = false;
×
963
                    }
964
                    else
965
                    {
966
                        for (const char *pszOtherDomain : apszDefaultDomains)
50✔
967
                        {
968
                            if (EQUAL(pszDomain, pszOtherDomain))
40✔
969
                            {
970
                                bCanCopy = false;
×
971
                                break;
×
972
                            }
973
                        }
974
                        if (!papszSrcMDD)
10✔
975
                        {
976
                            constexpr const char *const apszReservedDomains[] =
6✔
977
                                {"IMAGE_STRUCTURE", "DERIVED_SUBDATASETS"};
978
                            for (const char *pszOtherDomain :
6✔
979
                                 apszReservedDomains)
12✔
980
                            {
981
                                if (EQUAL(pszDomain, pszOtherDomain))
10✔
982
                                {
983
                                    bCanCopy = false;
4✔
984
                                    break;
4✔
985
                                }
986
                            }
987
                        }
988
                    }
989
                    if (bCanCopy)
10✔
990
                    {
991
                        poDstDS->SetMetadata(poSrcDS->GetMetadata(pszDomain),
6✔
992
                                             pszDomain);
6✔
993
                    }
994
                }
995
            }
996
        }
997
    }
998
    CSLDestroy(papszSrcMDD);
5,138✔
999
}
5,138✔
1000

1001
/************************************************************************/
1002
/*                      QuietDeleteForCreateCopy()                      */
1003
/************************************************************************/
1004

1005
CPLErr GDALDriver::QuietDeleteForCreateCopy(const char *pszFilename,
10,633✔
1006
                                            GDALDataset *poSrcDS)
1007
{
1008
    // Someone issuing CreateCopy("foo.tif") on a
1009
    // memory driver doesn't expect files with those names to be deleted
1010
    // on a file system...
1011
    // This is somewhat messy. Ideally there should be a way for the
1012
    // driver to overload the default behavior
1013
    if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
20,923✔
1014
        // Also exclude database formats for which there's no file list
1015
        // and whose opening might be slow (GeoRaster in particular)
1016
        !EQUAL(GetDescription(), "GeoRaster") &&
31,213✔
1017
        !EQUAL(GetDescription(), "PostGISRaster"))
10,290✔
1018
    {
1019
        /* --------------------------------------------------------------------
1020
         */
1021
        /*      Establish list of files of output dataset if it already
1022
         * exists. */
1023
        /* --------------------------------------------------------------------
1024
         */
1025
        std::set<std::string> oSetExistingDestFiles;
20,544✔
1026
        {
1027
            CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
20,544✔
1028
            const char *const apszAllowedDrivers[] = {GetDescription(),
10,272✔
1029
                                                      nullptr};
10,272✔
1030
            auto poExistingOutputDS =
1031
                std::unique_ptr<GDALDataset>(GDALDataset::Open(
1032
                    pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
20,544✔
1033
            if (poExistingOutputDS)
10,272✔
1034
            {
1035
                for (const char *pszFileInList :
676✔
1036
                     CPLStringList(poExistingOutputDS->GetFileList()))
644✔
1037
                {
1038
                    oSetExistingDestFiles.insert(
1039
                        CPLString(pszFileInList).replaceAll('\\', '/'));
338✔
1040
                }
1041
            }
1042
        }
1043

1044
        /* --------------------------------------------------------------------
1045
         */
1046
        /*      Check if the source dataset shares some files with the dest
1047
         * one.*/
1048
        /* --------------------------------------------------------------------
1049
         */
1050
        std::set<std::string> oSetExistingDestFilesFoundInSource;
20,544✔
1051
        if (!oSetExistingDestFiles.empty())
10,272✔
1052
        {
1053
            CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
612✔
1054
            // We need to reopen in a temporary dataset for the particular
1055
            // case of overwritten a .tif.ovr file from a .tif
1056
            // If we probe the file list of the .tif, it will then open the
1057
            // .tif.ovr !
1058
            const char *const apszAllowedDrivers[] = {
306✔
1059
                poSrcDS->GetDriver() ? poSrcDS->GetDriver()->GetDescription()
306✔
1060
                                     : nullptr,
1061
                nullptr};
306✔
1062
            auto poSrcDSTmp = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1063
                poSrcDS->GetDescription(), GDAL_OF_RASTER, apszAllowedDrivers,
306✔
1064
                poSrcDS->papszOpenOptions));
612✔
1065
            if (poSrcDSTmp)
306✔
1066
            {
1067
                for (const char *pszFileInList :
206✔
1068
                     CPLStringList(poSrcDSTmp->GetFileList()))
399✔
1069
                {
1070
                    CPLString osFilename(pszFileInList);
412✔
1071
                    osFilename.replaceAll('\\', '/');
206✔
1072
                    if (cpl::contains(oSetExistingDestFiles, osFilename))
206✔
1073
                    {
1074
                        oSetExistingDestFilesFoundInSource.insert(osFilename);
16✔
1075
                    }
1076
                }
1077
            }
1078
        }
1079

1080
        // If the source file(s) and the dest one share some files in
1081
        // common, only remove the files that are *not* in common
1082
        if (!oSetExistingDestFilesFoundInSource.empty())
10,272✔
1083
        {
1084
            for (const std::string &osFilename : oSetExistingDestFiles)
36✔
1085
            {
1086
                if (!cpl::contains(oSetExistingDestFilesFoundInSource,
21✔
1087
                                   osFilename))
1088
                {
1089
                    VSIUnlink(osFilename.c_str());
5✔
1090
                }
1091
            }
1092
        }
1093

1094
        QuietDelete(pszFilename);
10,272✔
1095
    }
1096

1097
    return CE_None;
10,633✔
1098
}
1099

1100
//! @endcond
1101

1102
/************************************************************************/
1103
/*                             CreateCopy()                             */
1104
/************************************************************************/
1105

1106
/**
1107
 * \brief Create a copy of a dataset.
1108
 *
1109
 * This method will attempt to create a copy of a raster dataset with the
1110
 * indicated filename, and in this drivers format.  Band number, size,
1111
 * type, projection, geotransform and so forth are all to be copied from
1112
 * the provided template dataset.
1113
 *
1114
 * Note that many sequential write once formats (such as JPEG and PNG) don't
1115
 * implement the Create() method but do implement this CreateCopy() method.
1116
 * If the driver doesn't implement CreateCopy(), but does implement Create()
1117
 * then the default CreateCopy() mechanism built on calling Create() will
1118
 * be used.
1119
 * So to test if CreateCopy() is available, you can test if GDAL_DCAP_CREATECOPY
1120
 * or GDAL_DCAP_CREATE is set in the GDAL metadata.
1121
 *
1122
 * It is intended that CreateCopy() will often be used with a source dataset
1123
 * which is a virtual dataset allowing configuration of band types, and other
1124
 * information without actually duplicating raster data (see the VRT driver).
1125
 * This is what is done by the gdal_translate utility for example.
1126
 *
1127
 * That function will try to validate the creation option list passed to the
1128
 * driver with the GDALValidateCreationOptions() method. This check can be
1129
 * disabled by defining the configuration option
1130
 * GDAL_VALIDATE_CREATION_OPTIONS=NO.
1131
 *
1132
 * This function copy all metadata from the default domain ("")
1133
 *
1134
 * Even is bStrict is TRUE, only the <b>value</b> of the data is equivalent,
1135
 * but the data layout (INTERLEAVE as PIXEL/LINE/BAND) of the dst dataset is
1136
 * controlled by the papszOptions creation options, and may differ from the
1137
 * poSrcDS src dataset.
1138
 * Starting from GDAL 3.5, if no INTERLEAVE and COMPRESS creation option has
1139
 * been specified in papszOptions, and if the driver supports equivalent
1140
 * interleaving as the src dataset, the CreateCopy() will internally add the
1141
 * proper creation option to get the same data interleaving.
1142
 *
1143
 * After you have finished working with the returned dataset, it is
1144
 * <b>required</b> to close it with GDALClose(). This does not only close the
1145
 * file handle, but also ensures that all the data and metadata has been written
1146
 * to the dataset (GDALFlushCache() is not sufficient for that purpose).
1147
 *
1148
 * For multidimensional datasets, papszOptions can contain array creation
1149
 * options, if they are prefixed with "ARRAY:". \see GDALGroup::CopyFrom()
1150
 * documentation for further details regarding such options.
1151
 *
1152
 * @param pszFilename the name for the new dataset.  UTF-8 encoded.
1153
 * @param poSrcDS the dataset being duplicated.
1154
 * @param bStrict TRUE if the copy must be strictly equivalent, or more
1155
 * normally FALSE indicating that the copy may adapt as needed for the
1156
 * output format.
1157
 * @param papszOptions additional format dependent options controlling
1158
 * creation of the output file.
1159
 * The APPEND_SUBDATASET=YES option can be specified to avoid prior destruction
1160
 * of existing dataset.
1161
 * Starting with GDAL 3.8.0, the following options are recognized by the
1162
 * GTiff, COG, VRT, PNG au JPEG drivers:
1163
 * <ul>
1164
 * <li>COPY_SRC_MDD=AUTO/YES/NO: whether metadata domains of the source dataset
1165
 * should be copied to the destination dataset. In the default AUTO mode, only
1166
 * "safe" domains will be copied, which include the default metadata domain
1167
 * (some drivers may include other domains such as IMD, RPC, GEOLOCATION). When
1168
 * setting YES, all domains will be copied (but a few reserved ones like
1169
 * IMAGE_STRUCTURE or DERIVED_SUBDATASETS). When setting NO, no source metadata
1170
 * will be copied.
1171
 * </li>
1172
 *<li>SRC_MDD=domain_name: which source metadata domain should be copied.
1173
 * This option restricts the list of source metadata domains to be copied
1174
 * (it implies COPY_SRC_MDD=YES if it is not set). This option may be specified
1175
 * as many times as they are source domains. The default metadata domain is the
1176
 * empty string "" ("_DEFAULT_") may also be used when empty string is not practical)
1177
 * </li>
1178
 * </ul>
1179
 * @param pfnProgress a function to be used to report progress of the copy.
1180
 * @param pProgressData application data passed into progress function.
1181
 *
1182
 * @return a pointer to the newly created dataset (may be read-only access).
1183
 */
1184

1185
GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
10,368✔
1186
                                    GDALDataset *poSrcDS, int bStrict,
1187
                                    CSLConstList papszOptions,
1188
                                    GDALProgressFunc pfnProgress,
1189
                                    void *pProgressData)
1190

1191
{
1192
    if (pfnProgress == nullptr)
10,368✔
1193
        pfnProgress = GDALDummyProgress;
8,091✔
1194

1195
    const int nBandCount = poSrcDS->GetRasterCount();
10,368✔
1196

1197
    /* -------------------------------------------------------------------- */
1198
    /*      If no INTERLEAVE creation option is given, we will try to add   */
1199
    /*      one that matches the current srcDS interleaving                 */
1200
    /* -------------------------------------------------------------------- */
1201
    char **papszOptionsToDelete = nullptr;
10,368✔
1202
    const char *srcInterleave =
1203
        poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
10,368✔
1204
    if (nBandCount > 1 && srcInterleave != nullptr &&
6,404✔
1205
        CSLFetchNameValue(papszOptions, "INTERLEAVE") == nullptr &&
17,339✔
1206
        EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
567✔
1207
    {
1208

1209
        // look for INTERLEAVE values of the driver
1210
        char **interleavesCSL = nullptr;
431✔
1211
        const char *pszOptionList =
1212
            this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
431✔
1213
        CPLXMLNode *xmlNode =
1214
            !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
431✔
1215
        for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
431✔
1216
             child != nullptr; child = child->psNext)
9,663✔
1217
        {
1218
            if ((child->eType == CXT_Element) &&
9,232✔
1219
                EQUAL(child->pszValue, "Option"))
9,232✔
1220
            {
1221
                const char *nameAttribute =
1222
                    CPLGetXMLValue(child, "name", nullptr);
9,232✔
1223
                const bool isInterleaveAttribute =
9,232✔
1224
                    nameAttribute && EQUAL(nameAttribute, "INTERLEAVE");
9,232✔
1225
                if (isInterleaveAttribute)
9,232✔
1226
                {
1227
                    for (CPLXMLNode *optionChild = child->psChild;
203✔
1228
                         optionChild != nullptr;
1,246✔
1229
                         optionChild = optionChild->psNext)
1,043✔
1230
                    {
1231
                        if ((optionChild->eType == CXT_Element) &&
1,043✔
1232
                            EQUAL(optionChild->pszValue, "Value"))
429✔
1233
                        {
1234
                            CPLXMLNode *optionChildValue = optionChild->psChild;
429✔
1235
                            if (optionChildValue &&
429✔
1236
                                (optionChildValue->eType == CXT_Text))
429✔
1237
                            {
1238
                                interleavesCSL = CSLAddString(
429✔
1239
                                    interleavesCSL, optionChildValue->pszValue);
429✔
1240
                            }
1241
                        }
1242
                    }
1243
                }
1244
            }
1245
        }
1246
        CPLDestroyXMLNode(xmlNode);
431✔
1247

1248
        const char *dstInterleaveBand =
1249
            (CSLFindString(interleavesCSL, "BAND") >= 0)  ? "BAND"
665✔
1250
            : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
234✔
1251
                                                          : nullptr;
431✔
1252
        const char *dstInterleaveLine =
1253
            (CSLFindString(interleavesCSL, "LINE") >= 0)  ? "LINE"
862✔
1254
            : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
431✔
1255
                                                          : nullptr;
431✔
1256
        const char *dstInterleavePixel =
1257
            (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
665✔
1258
            : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
234✔
1259
                                                          : nullptr;
431✔
1260
        const char *dstInterleave =
431✔
1261
            EQUAL(srcInterleave, "BAND")    ? dstInterleaveBand
690✔
1262
            : EQUAL(srcInterleave, "LINE")  ? dstInterleaveLine
516✔
1263
            : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
257✔
1264
                                            : nullptr;
1265
        CSLDestroy(interleavesCSL);
431✔
1266

1267
        if (dstInterleave != nullptr)
431✔
1268
        {
1269
            papszOptionsToDelete = CSLDuplicate(papszOptions);
203✔
1270
            papszOptionsToDelete = CSLSetNameValue(papszOptionsToDelete,
203✔
1271
                                                   "INTERLEAVE", dstInterleave);
1272
            papszOptionsToDelete = CSLSetNameValue(
203✔
1273
                papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1274
            papszOptions = papszOptionsToDelete;
203✔
1275
        }
1276
    }
1277

1278
    /* -------------------------------------------------------------------- */
1279
    /*      Make sure we cleanup if there is an existing dataset of this    */
1280
    /*      name.  But even if that seems to fail we will continue since    */
1281
    /*      it might just be a corrupt file or something.                   */
1282
    /* -------------------------------------------------------------------- */
1283
    const bool bAppendSubdataset =
1284
        CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false);
10,368✔
1285
    // Note: @QUIET_DELETE_ON_CREATE_COPY is set to NO by the KMLSuperOverlay
1286
    // driver when writing a .kmz file. Also by GDALTranslate() if it has
1287
    // already done a similar job.
1288
    if (!bAppendSubdataset &&
20,716✔
1289
        CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
10,348✔
1290
    {
1291
        QuietDeleteForCreateCopy(pszFilename, poSrcDS);
8,334✔
1292
    }
1293

1294
    int iIdxQuietDeleteOnCreateCopy =
1295
        CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
10,368✔
1296
    if (iIdxQuietDeleteOnCreateCopy >= 0)
10,368✔
1297
    {
1298
        if (papszOptionsToDelete == nullptr)
2,014✔
1299
            papszOptionsToDelete = CSLDuplicate(papszOptions);
1,877✔
1300
        papszOptionsToDelete = CSLRemoveStrings(
2,014✔
1301
            papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1302
        papszOptions = papszOptionsToDelete;
2,014✔
1303
    }
1304

1305
    /* -------------------------------------------------------------------- */
1306
    /*      If _INTERNAL_DATASET=YES, the returned dataset will not be      */
1307
    /*      registered in the global list of open datasets.                 */
1308
    /* -------------------------------------------------------------------- */
1309
    const int iIdxInternalDataset =
1310
        CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
10,368✔
1311
    bool bInternalDataset = false;
10,368✔
1312
    if (iIdxInternalDataset >= 0)
10,368✔
1313
    {
1314
        bInternalDataset =
1315
            CPLFetchBool(papszOptions, "_INTERNAL_DATASET", false);
4,163✔
1316
        if (papszOptionsToDelete == nullptr)
4,163✔
1317
            papszOptionsToDelete = CSLDuplicate(papszOptions);
4,163✔
1318
        papszOptionsToDelete = CSLRemoveStrings(
4,163✔
1319
            papszOptionsToDelete, iIdxInternalDataset, 1, nullptr);
1320
        papszOptions = papszOptionsToDelete;
4,163✔
1321
    }
1322

1323
    /* -------------------------------------------------------------------- */
1324
    /*      Validate creation options.                                      */
1325
    /* -------------------------------------------------------------------- */
1326
    if (CPLTestBool(
10,368✔
1327
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1328
    {
1329
        auto poSrcGroup = poSrcDS->GetRootGroup();
20,736✔
1330
        if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
10,368✔
1331
        {
1332
            CPLStringList aosDatasetCO;
178✔
1333
            for (const char *pszOption : cpl::Iterate(papszOptions))
96✔
1334
            {
1335
                if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
7✔
1336
                    aosDatasetCO.AddString(pszOption);
×
1337
            }
1338
            GDALValidateCreationOptions(this, aosDatasetCO.List());
89✔
1339
        }
1340
        else
1341
        {
1342
            GDALValidateCreationOptions(this, papszOptions);
10,279✔
1343
        }
1344
    }
1345

1346
    /* -------------------------------------------------------------------- */
1347
    /*      Advise the source raster that we are going to read it completely */
1348
    /* -------------------------------------------------------------------- */
1349

1350
    const int nXSize = poSrcDS->GetRasterXSize();
10,368✔
1351
    const int nYSize = poSrcDS->GetRasterYSize();
10,368✔
1352
    GDALDataType eDT = GDT_Unknown;
10,368✔
1353
    if (nBandCount > 0)
10,368✔
1354
    {
1355
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
10,168✔
1356
        if (poSrcBand)
10,168✔
1357
            eDT = poSrcBand->GetRasterDataType();
10,168✔
1358
    }
1359
    poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
10,368✔
1360
                        nullptr, nullptr);
10,368✔
1361

1362
    /* -------------------------------------------------------------------- */
1363
    /*      If the format provides a CreateCopy() method use that,          */
1364
    /*      otherwise fallback to the internal implementation using the     */
1365
    /*      Create() method.                                                */
1366
    /* -------------------------------------------------------------------- */
1367
    GDALDataset *poDstDS = nullptr;
10,368✔
1368
    auto l_pfnCreateCopy = GetCreateCopyCallback();
10,368✔
1369
    if (l_pfnCreateCopy != nullptr &&
19,852✔
1370
        !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
9,484✔
1371
    {
1372
        poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
9,484✔
1373
                                  const_cast<char **>(papszOptions),
1374
                                  pfnProgress, pProgressData);
1375
        if (poDstDS != nullptr)
9,484✔
1376
        {
1377
            if (poDstDS->GetDescription() == nullptr ||
16,874✔
1378
                strlen(poDstDS->GetDescription()) == 0)
8,437✔
1379
                poDstDS->SetDescription(pszFilename);
186✔
1380

1381
            if (poDstDS->poDriver == nullptr)
8,437✔
1382
                poDstDS->poDriver = this;
7,542✔
1383

1384
            if (!bInternalDataset)
8,437✔
1385
                poDstDS->AddToDatasetOpenList();
4,274✔
1386
        }
1387
    }
1388
    else
1389
    {
1390
        poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
884✔
1391
                                    pfnProgress, pProgressData);
1392
    }
1393

1394
    CSLDestroy(papszOptionsToDelete);
10,368✔
1395
    return poDstDS;
10,368✔
1396
}
1397

1398
/************************************************************************/
1399
/*                           GDALCreateCopy()                           */
1400
/************************************************************************/
1401

1402
/**
1403
 * \brief Create a copy of a dataset.
1404
 *
1405
 * @see GDALDriver::CreateCopy()
1406
 */
1407

1408
GDALDatasetH CPL_STDCALL GDALCreateCopy(GDALDriverH hDriver,
5,812✔
1409
                                        const char *pszFilename,
1410
                                        GDALDatasetH hSrcDS, int bStrict,
1411
                                        CSLConstList papszOptions,
1412
                                        GDALProgressFunc pfnProgress,
1413
                                        void *pProgressData)
1414

1415
{
1416
    VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
5,812✔
1417
    VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
5,812✔
1418

1419
    return GDALDriver::FromHandle(hDriver)->CreateCopy(
5,812✔
1420
        pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1421
        pfnProgress, pProgressData);
5,812✔
1422
}
1423

1424
/************************************************************************/
1425
/*                      CanVectorTranslateFrom()                        */
1426
/************************************************************************/
1427

1428
/** Returns whether the driver can translate from a vector dataset,
1429
 * using the arguments passed to GDALVectorTranslate() stored in
1430
 * papszVectorTranslateArguments.
1431
 *
1432
 * This is used to determine if the driver supports the VectorTranslateFrom()
1433
 * operation.
1434
 *
1435
 * @param pszDestName Target dataset name
1436
 * @param poSourceDS  Source dataset
1437
 * @param papszVectorTranslateArguments Non-positional arguments passed to
1438
 *                                      GDALVectorTranslate() (may be nullptr)
1439
 * @param[out] ppapszFailureReasons nullptr, or a pointer to an null-terminated
1440
 * array of strings to record the reason(s) for the impossibility.
1441
 * @return true if VectorTranslateFrom() can be called with the same arguments.
1442
 * @since GDAL 3.8
1443
 */
1444
bool GDALDriver::CanVectorTranslateFrom(
728✔
1445
    const char *pszDestName, GDALDataset *poSourceDS,
1446
    CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1447

1448
{
1449
    if (ppapszFailureReasons)
728✔
1450
    {
1451
        *ppapszFailureReasons = nullptr;
×
1452
    }
1453

1454
    if (!pfnCanVectorTranslateFrom)
728✔
1455
    {
1456
        if (ppapszFailureReasons)
725✔
1457
        {
1458
            *ppapszFailureReasons = CSLAddString(
×
1459
                nullptr,
1460
                "CanVectorTranslateFrom() not implemented for this driver");
1461
        }
1462
        return false;
725✔
1463
    }
1464

1465
    char **papszFailureReasons = nullptr;
3✔
1466
    bool bRet = pfnCanVectorTranslateFrom(
3✔
1467
        pszDestName, poSourceDS, papszVectorTranslateArguments,
1468
        ppapszFailureReasons ? ppapszFailureReasons : &papszFailureReasons);
1469
    if (!ppapszFailureReasons)
3✔
1470
    {
1471
        for (const char *pszReason :
1✔
1472
             cpl::Iterate(static_cast<CSLConstList>(papszFailureReasons)))
5✔
1473
        {
1474
            CPLDebug("GDAL", "%s", pszReason);
1✔
1475
        }
1476
        CSLDestroy(papszFailureReasons);
3✔
1477
    }
1478
    return bRet;
3✔
1479
}
1480

1481
bool GDALDriver::HasOpenOption(const char *pszOpenOptionName) const
224✔
1482
{
1483
    if (pszOpenOptionName == nullptr)
224✔
1484
        return false;
×
1485

1486
    // Const cast is safe here since we are only reading the metadata
1487
    auto pszOOMd{const_cast<GDALDriver *>(this)->GetMetadataItem(
448✔
1488
        GDAL_DMD_OPENOPTIONLIST)};
224✔
1489
    if (pszOOMd == nullptr)
224✔
1490
        return false;
72✔
1491

1492
    const CPLXMLTreeCloser oXml{CPLParseXMLString(pszOOMd)};
304✔
1493
    for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1,159✔
1494
         option = option->psNext)
1,007✔
1495
    {
1496
        if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1,008✔
1497
                  pszOpenOptionName))
1498
            return true;
1✔
1499
    }
1500
    return false;
151✔
1501
}
1502

1503
/************************************************************************/
1504
/*                         VectorTranslateFrom()                        */
1505
/************************************************************************/
1506

1507
/** Create a copy of a vector dataset, using the arguments passed to
1508
 * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1509
 *
1510
 * This may be implemented by some drivers that can convert from an existing
1511
 * dataset in an optimized way.
1512
 *
1513
 * This is for example used by the PMTiles to convert from MBTiles.
1514
 *
1515
 * @param pszDestName Target dataset name
1516
 * @param poSourceDS  Source dataset
1517
 * @param papszVectorTranslateArguments Non-positional arguments passed to
1518
 *                                      GDALVectorTranslate() (may be nullptr)
1519
 * @param pfnProgress a function to be used to report progress of the copy.
1520
 * @param pProgressData application data passed into progress function.
1521
 * @return a new dataset in case of success, or nullptr in case of error.
1522
 * @since GDAL 3.8
1523
 */
1524
GDALDataset *GDALDriver::VectorTranslateFrom(
2✔
1525
    const char *pszDestName, GDALDataset *poSourceDS,
1526
    CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1527
    void *pProgressData)
1528

1529
{
1530
    if (!pfnVectorTranslateFrom)
2✔
1531
    {
1532
        CPLError(CE_Failure, CPLE_AppDefined,
×
1533
                 "VectorTranslateFrom() not implemented for this driver");
1534
        return nullptr;
×
1535
    }
1536

1537
    return pfnVectorTranslateFrom(pszDestName, poSourceDS,
2✔
1538
                                  papszVectorTranslateArguments, pfnProgress,
1539
                                  pProgressData);
2✔
1540
}
1541

1542
/************************************************************************/
1543
/*                            QuietDelete()                             */
1544
/************************************************************************/
1545

1546
/**
1547
 * \brief Delete dataset if found.
1548
 *
1549
 * This is a helper method primarily used by Create() and
1550
 * CreateCopy() to predelete any dataset of the name soon to be
1551
 * created.  It will attempt to delete the named dataset if
1552
 * one is found, otherwise it does nothing.  An error is only
1553
 * returned if the dataset is found but the delete fails.
1554
 *
1555
 * This is a static method and it doesn't matter what driver instance
1556
 * it is invoked on.  It will attempt to discover the correct driver
1557
 * using Identify().
1558
 *
1559
 * @param pszName the dataset name to try and delete.
1560
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1561
 * terminated list of strings with the driver short names that must be
1562
 * considered. (Note: implemented only starting with GDAL 3.4.1)
1563
 * @return CE_None if the dataset does not exist, or is deleted without issues.
1564
 */
1565

1566
CPLErr GDALDriver::QuietDelete(const char *pszName,
20,579✔
1567
                               CSLConstList papszAllowedDrivers)
1568

1569
{
1570
    VSIStatBufL sStat;
1571
    const bool bExists =
1572
        VSIStatExL(pszName, &sStat,
20,579✔
1573
                   VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
20,579✔
1574

1575
#ifdef S_ISFIFO
1576
    if (bExists && S_ISFIFO(sStat.st_mode))
20,579✔
1577
        return CE_None;
×
1578
#endif
1579

1580
    if (bExists && VSI_ISDIR(sStat.st_mode))
20,579✔
1581
    {
1582
        // It is not desirable to remove directories quietly.  Necessary to
1583
        // avoid ogr_mitab_12 to destroy file created at ogr_mitab_7.
1584
        return CE_None;
98✔
1585
    }
1586

1587
    GDALDriver *poDriver = nullptr;
20,481✔
1588
    if (papszAllowedDrivers)
20,481✔
1589
    {
1590
        GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
×
1591
        for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
×
1592
        {
1593
            GDALDriver *poTmpDriver =
1594
                GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
×
1595
            if (poTmpDriver)
×
1596
            {
1597
                const bool bIdentifyRes =
1598
                    poTmpDriver->pfnIdentifyEx
×
1599
                        ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
×
1600
                              0
1601
                        : poTmpDriver->pfnIdentify &&
×
1602
                              poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
×
1603
                if (bIdentifyRes)
×
1604
                {
1605
                    poDriver = poTmpDriver;
×
1606
                    break;
×
1607
                }
1608
            }
1609
        }
1610
    }
1611
    else
1612
    {
1613
        CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
40,962✔
1614
        poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
20,481✔
1615
    }
1616

1617
    if (poDriver == nullptr)
20,481✔
1618
        return CE_None;
19,593✔
1619

1620
    CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
888✔
1621

1622
    poDriver->pfnDelete = poDriver->GetDeleteCallback();
888✔
1623
    const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
926✔
1624
                        poDriver->pfnDeleteDataSource == nullptr;
38✔
1625
    if (bQuiet)
888✔
1626
    {
1627
        CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
76✔
1628
        return poDriver->Delete(pszName);
38✔
1629
    }
1630
    else
1631
    {
1632
        return poDriver->Delete(pszName);
850✔
1633
    }
1634
}
1635

1636
/************************************************************************/
1637
/*                               Delete()                               */
1638
/************************************************************************/
1639

1640
/**
1641
 * \brief Delete named dataset.
1642
 *
1643
 * The driver will attempt to delete the named dataset in a driver specific
1644
 * fashion.  Full featured drivers will delete all associated files,
1645
 * database objects, or whatever is appropriate.  The default behavior when
1646
 * no driver specific behavior is provided is to attempt to delete all the
1647
 * files that are returned by GDALGetFileList() on the dataset handle.
1648
 *
1649
 * It is unwise to have open dataset handles on this dataset when it is
1650
 * deleted.
1651
 *
1652
 * Equivalent of the C function GDALDeleteDataset().
1653
 *
1654
 * @param pszFilename name of dataset to delete.
1655
 *
1656
 * @return CE_None on success, or CE_Failure if the operation fails.
1657
 */
1658

1659
CPLErr GDALDriver::Delete(const char *pszFilename)
4,499✔
1660

1661
{
1662
    pfnDelete = GetDeleteCallback();
4,499✔
1663
    if (pfnDelete != nullptr)
4,499✔
1664
        return pfnDelete(pszFilename);
1,070✔
1665
    else if (pfnDeleteDataSource != nullptr)
3,429✔
1666
        return pfnDeleteDataSource(this, pszFilename);
×
1667

1668
    /* -------------------------------------------------------------------- */
1669
    /*      Collect file list.                                              */
1670
    /* -------------------------------------------------------------------- */
1671
    GDALDatasetH hDS = GDALOpenEx(pszFilename, 0, nullptr, nullptr, nullptr);
3,429✔
1672

1673
    if (hDS == nullptr)
3,429✔
1674
    {
1675
        if (CPLGetLastErrorNo() == 0)
232✔
1676
            CPLError(CE_Failure, CPLE_OpenFailed,
206✔
1677
                     "Unable to open %s to obtain file list.", pszFilename);
1678

1679
        return CE_Failure;
232✔
1680
    }
1681

1682
    char **papszFileList = GDALGetFileList(hDS);
3,197✔
1683

1684
    GDALClose(hDS);
3,197✔
1685
    hDS = nullptr;
3,197✔
1686

1687
    if (CSLCount(papszFileList) == 0)
3,197✔
1688
    {
1689
        CPLError(CE_Failure, CPLE_NotSupported,
×
1690
                 "Unable to determine files associated with %s, "
1691
                 "delete fails.",
1692
                 pszFilename);
1693
        CSLDestroy(papszFileList);
×
1694
        return CE_Failure;
×
1695
    }
1696

1697
    /* -------------------------------------------------------------------- */
1698
    /*      Delete all files.                                               */
1699
    /* -------------------------------------------------------------------- */
1700
    CPLErr eErr = CE_None;
3,197✔
1701
    for (int i = 0; papszFileList[i] != nullptr; ++i)
7,080✔
1702
    {
1703
        if (VSIUnlink(papszFileList[i]) != 0)
3,883✔
1704
        {
1705
            CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
×
1706
                     papszFileList[i], VSIStrerror(errno));
×
1707
            eErr = CE_Failure;
×
1708
        }
1709
    }
1710

1711
    CSLDestroy(papszFileList);
3,197✔
1712

1713
    return eErr;
3,197✔
1714
}
1715

1716
/************************************************************************/
1717
/*                         GDALDeleteDataset()                          */
1718
/************************************************************************/
1719

1720
/**
1721
 * \brief Delete named dataset.
1722
 *
1723
 * @see GDALDriver::Delete()
1724
 */
1725

1726
CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
2,487✔
1727
                                     const char *pszFilename)
1728

1729
{
1730
    if (hDriver == nullptr)
2,487✔
1731
        hDriver = GDALIdentifyDriver(pszFilename, nullptr);
8✔
1732

1733
    if (hDriver == nullptr)
2,487✔
1734
    {
1735
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
×
1736
                 pszFilename);
1737
        return CE_Failure;
×
1738
    }
1739

1740
#ifdef OGRAPISPY_ENABLED
1741
    if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
2,487✔
1742
    {
1743
        OGRAPISpyDeleteDataSource(hDriver, pszFilename);
484✔
1744
    }
1745
#endif
1746

1747
    return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
2,487✔
1748
}
1749

1750
/************************************************************************/
1751
/*                           DefaultRename()                            */
1752
/*                                                                      */
1753
/*      The generic implementation based on the file list used when     */
1754
/*      there is no format specific implementation.                     */
1755
/************************************************************************/
1756

1757
//! @cond Doxygen_Suppress
1758
CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
172✔
1759

1760
{
1761
    /* -------------------------------------------------------------------- */
1762
    /*      Collect file list.                                              */
1763
    /* -------------------------------------------------------------------- */
1764
    GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
172✔
1765

1766
    if (hDS == nullptr)
172✔
1767
    {
1768
        if (CPLGetLastErrorNo() == 0)
×
1769
            CPLError(CE_Failure, CPLE_OpenFailed,
×
1770
                     "Unable to open %s to obtain file list.", pszOldName);
1771

1772
        return CE_Failure;
×
1773
    }
1774

1775
    char **papszFileList = GDALGetFileList(hDS);
172✔
1776

1777
    GDALClose(hDS);
172✔
1778

1779
    if (CSLCount(papszFileList) == 0)
172✔
1780
    {
1781
        CPLError(CE_Failure, CPLE_NotSupported,
×
1782
                 "Unable to determine files associated with %s,\n"
1783
                 "rename fails.",
1784
                 pszOldName);
1785

1786
        return CE_Failure;
×
1787
    }
1788

1789
    /* -------------------------------------------------------------------- */
1790
    /*      Produce a list of new filenames that correspond to the old      */
1791
    /*      names.                                                          */
1792
    /* -------------------------------------------------------------------- */
1793
    CPLErr eErr = CE_None;
172✔
1794
    char **papszNewFileList =
1795
        CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
172✔
1796

1797
    if (papszNewFileList == nullptr)
172✔
1798
        return CE_Failure;
×
1799

1800
    for (int i = 0; papszFileList[i] != nullptr; ++i)
351✔
1801
    {
1802
        if (CPLMoveFile(papszNewFileList[i], papszFileList[i]) != 0)
179✔
1803
        {
1804
            eErr = CE_Failure;
×
1805
            // Try to put the ones we moved back.
1806
            for (--i; i >= 0; i--)
×
1807
            {
1808
                // Nothing we can do if the moving back doesn't work...
1809
                CPL_IGNORE_RET_VAL(
×
1810
                    CPLMoveFile(papszFileList[i], papszNewFileList[i]));
×
1811
            }
1812
            break;
×
1813
        }
1814
    }
1815

1816
    CSLDestroy(papszNewFileList);
172✔
1817
    CSLDestroy(papszFileList);
172✔
1818

1819
    return eErr;
172✔
1820
}
1821

1822
//! @endcond
1823

1824
/************************************************************************/
1825
/*                               Rename()                               */
1826
/************************************************************************/
1827

1828
/**
1829
 * \brief Rename a dataset.
1830
 *
1831
 * Rename a dataset. This may including moving the dataset to a new directory
1832
 * or even a new filesystem.
1833
 *
1834
 * It is unwise to have open dataset handles on this dataset when it is
1835
 * being renamed.
1836
 *
1837
 * Equivalent of the C function GDALRenameDataset().
1838
 *
1839
 * @param pszNewName new name for the dataset.
1840
 * @param pszOldName old name for the dataset.
1841
 *
1842
 * @return CE_None on success, or CE_Failure if the operation fails.
1843
 */
1844

1845
CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
174✔
1846

1847
{
1848
    pfnRename = GetRenameCallback();
174✔
1849
    if (pfnRename != nullptr)
174✔
1850
        return pfnRename(pszNewName, pszOldName);
3✔
1851

1852
    return DefaultRename(pszNewName, pszOldName);
171✔
1853
}
1854

1855
/************************************************************************/
1856
/*                         GDALRenameDataset()                          */
1857
/************************************************************************/
1858

1859
/**
1860
 * \brief Rename a dataset.
1861
 *
1862
 * @see GDALDriver::Rename()
1863
 */
1864

1865
CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
174✔
1866
                                     const char *pszNewName,
1867
                                     const char *pszOldName)
1868

1869
{
1870
    if (hDriver == nullptr)
174✔
1871
        hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1✔
1872

1873
    if (hDriver == nullptr)
174✔
1874
    {
1875
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
×
1876
                 pszOldName);
1877
        return CE_Failure;
×
1878
    }
1879

1880
    return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
174✔
1881
}
1882

1883
/************************************************************************/
1884
/*                          DefaultCopyFiles()                          */
1885
/*                                                                      */
1886
/*      The default implementation based on file lists used when        */
1887
/*      there is no format specific implementation.                     */
1888
/************************************************************************/
1889

1890
//! @cond Doxygen_Suppress
1891
CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
7✔
1892
                                    const char *pszOldName)
1893

1894
{
1895
    /* -------------------------------------------------------------------- */
1896
    /*      Collect file list.                                              */
1897
    /* -------------------------------------------------------------------- */
1898
    GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
7✔
1899

1900
    if (hDS == nullptr)
7✔
1901
    {
1902
        if (CPLGetLastErrorNo() == 0)
×
1903
            CPLError(CE_Failure, CPLE_OpenFailed,
×
1904
                     "Unable to open %s to obtain file list.", pszOldName);
1905

1906
        return CE_Failure;
×
1907
    }
1908

1909
    char **papszFileList = GDALGetFileList(hDS);
7✔
1910

1911
    GDALClose(hDS);
7✔
1912
    hDS = nullptr;
7✔
1913

1914
    if (CSLCount(papszFileList) == 0)
7✔
1915
    {
1916
        CPLError(CE_Failure, CPLE_NotSupported,
×
1917
                 "Unable to determine files associated with %s,\n"
1918
                 "rename fails.",
1919
                 pszOldName);
1920

1921
        return CE_Failure;
×
1922
    }
1923

1924
    /* -------------------------------------------------------------------- */
1925
    /*      Produce a list of new filenames that correspond to the old      */
1926
    /*      names.                                                          */
1927
    /* -------------------------------------------------------------------- */
1928
    CPLErr eErr = CE_None;
7✔
1929
    char **papszNewFileList =
1930
        CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
7✔
1931

1932
    if (papszNewFileList == nullptr)
7✔
1933
        return CE_Failure;
×
1934

1935
    for (int i = 0; papszFileList[i] != nullptr; ++i)
22✔
1936
    {
1937
        if (CPLCopyFile(papszNewFileList[i], papszFileList[i]) != 0)
15✔
1938
        {
1939
            eErr = CE_Failure;
×
1940
            // Try to put the ones we moved back.
1941
            for (--i; i >= 0; --i)
×
1942
                VSIUnlink(papszNewFileList[i]);
×
1943
            break;
×
1944
        }
1945
    }
1946

1947
    CSLDestroy(papszNewFileList);
7✔
1948
    CSLDestroy(papszFileList);
7✔
1949

1950
    return eErr;
7✔
1951
}
1952

1953
//! @endcond
1954

1955
/************************************************************************/
1956
/*                             CopyFiles()                              */
1957
/************************************************************************/
1958

1959
/**
1960
 * \brief Copy the files of a dataset.
1961
 *
1962
 * Copy all the files associated with a dataset.
1963
 *
1964
 * Equivalent of the C function GDALCopyDatasetFiles().
1965
 *
1966
 * @param pszNewName new name for the dataset.
1967
 * @param pszOldName old name for the dataset.
1968
 *
1969
 * @return CE_None on success, or CE_Failure if the operation fails.
1970
 */
1971

1972
CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
9✔
1973

1974
{
1975
    pfnCopyFiles = GetCopyFilesCallback();
9✔
1976
    if (pfnCopyFiles != nullptr)
9✔
1977
        return pfnCopyFiles(pszNewName, pszOldName);
3✔
1978

1979
    return DefaultCopyFiles(pszNewName, pszOldName);
6✔
1980
}
1981

1982
/************************************************************************/
1983
/*                        GDALCopyDatasetFiles()                        */
1984
/************************************************************************/
1985

1986
/**
1987
 * \brief Copy the files of a dataset.
1988
 *
1989
 * @see GDALDriver::CopyFiles()
1990
 */
1991

1992
CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
9✔
1993
                                        const char *pszNewName,
1994
                                        const char *pszOldName)
1995

1996
{
1997
    if (hDriver == nullptr)
9✔
1998
        hDriver = GDALIdentifyDriver(pszOldName, nullptr);
5✔
1999

2000
    if (hDriver == nullptr)
9✔
2001
    {
2002
        CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
×
2003
                 pszOldName);
2004
        return CE_Failure;
×
2005
    }
2006

2007
    return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
9✔
2008
}
2009

2010
/************************************************************************/
2011
/*                       GDALDriverHasOpenOption()                      */
2012
/************************************************************************/
2013

2014
/**
2015
 * \brief Returns TRUE if the given open option is supported by the driver.
2016
 * @param hDriver the handle of the driver
2017
 * @param pszOpenOptionName name of the open option to be checked
2018
 * @return TRUE if the driver supports the open option
2019
 * @since GDAL 3.11
2020
 */
2021
bool GDALDriverHasOpenOption(GDALDriverH hDriver, const char *pszOpenOptionName)
2✔
2022
{
2023
    VALIDATE_POINTER1(hDriver, "GDALDriverHasOpenOption", false);
2✔
2024
    return GDALDriver::FromHandle(hDriver)->HasOpenOption(pszOpenOptionName);
2✔
2025
}
2026

2027
/************************************************************************/
2028
/*                       GDALGetDriverShortName()                       */
2029
/************************************************************************/
2030

2031
/**
2032
 * \brief Return the short name of a driver
2033
 *
2034
 * This is the string that can be
2035
 * passed to the GDALGetDriverByName() function.
2036
 *
2037
 * For the GeoTIFF driver, this is "GTiff"
2038
 *
2039
 * @param hDriver the handle of the driver
2040
 * @return the short name of the driver. The
2041
 *         returned string should not be freed and is owned by the driver.
2042
 */
2043

2044
const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
3,288,580✔
2045

2046
{
2047
    VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
3,288,580✔
2048

2049
    return GDALDriver::FromHandle(hDriver)->GetDescription();
3,288,580✔
2050
}
2051

2052
/************************************************************************/
2053
/*                       GDALGetDriverLongName()                        */
2054
/************************************************************************/
2055

2056
/**
2057
 * \brief Return the long name of a driver
2058
 *
2059
 * For the GeoTIFF driver, this is "GeoTIFF"
2060
 *
2061
 * @param hDriver the handle of the driver
2062
 * @return the long name of the driver or empty string. The
2063
 *         returned string should not be freed and is owned by the driver.
2064
 */
2065

2066
const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
467✔
2067

2068
{
2069
    VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
467✔
2070

2071
    const char *pszLongName =
2072
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
467✔
2073

2074
    if (pszLongName == nullptr)
467✔
2075
        return "";
×
2076

2077
    return pszLongName;
467✔
2078
}
2079

2080
/************************************************************************/
2081
/*                       GDALGetDriverHelpTopic()                       */
2082
/************************************************************************/
2083

2084
/**
2085
 * \brief Return the URL to the help that describes the driver
2086
 *
2087
 * That URL is relative to the GDAL documentation directory.
2088
 *
2089
 * For the GeoTIFF driver, this is "frmt_gtiff.html"
2090
 *
2091
 * @param hDriver the handle of the driver
2092
 * @return the URL to the help that describes the driver or NULL. The
2093
 *         returned string should not be freed and is owned by the driver.
2094
 */
2095

2096
const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
×
2097

2098
{
2099
    VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
×
2100

2101
    return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
×
2102
}
2103

2104
/************************************************************************/
2105
/*                   GDALGetDriverCreationOptionList()                  */
2106
/************************************************************************/
2107

2108
/**
2109
 * \brief Return the list of creation options of the driver
2110
 *
2111
 * Return the list of creation options of the driver used by Create() and
2112
 * CreateCopy() as an XML string
2113
 *
2114
 * @param hDriver the handle of the driver
2115
 * @return an XML string that describes the list of creation options or
2116
 *         empty string. The returned string should not be freed and is
2117
 *         owned by the driver.
2118
 */
2119

2120
const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
×
2121

2122
{
2123
    VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
×
2124

2125
    const char *pszOptionList =
2126
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
×
2127
            GDAL_DMD_CREATIONOPTIONLIST);
×
2128

2129
    if (pszOptionList == nullptr)
×
2130
        return "";
×
2131

2132
    return pszOptionList;
×
2133
}
2134

2135
/************************************************************************/
2136
/*                   GDALValidateCreationOptions()                      */
2137
/************************************************************************/
2138

2139
/**
2140
 * \brief Validate the list of creation options that are handled by a driver
2141
 *
2142
 * This is a helper method primarily used by Create() and
2143
 * CreateCopy() to validate that the passed in list of creation options
2144
 * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2145
 * by some drivers. @see GDALGetDriverCreationOptionList()
2146
 *
2147
 * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2148
 * function will return TRUE. Otherwise it will check that the keys and values
2149
 * in the list of creation options are compatible with the capabilities declared
2150
 * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2151
 * a (non fatal) warning will be emitted and FALSE will be returned.
2152
 *
2153
 * @param hDriver the handle of the driver with whom the lists of creation
2154
 * option must be validated
2155
 * @param papszCreationOptions the list of creation options. An array of
2156
 * strings, whose last element is a NULL pointer
2157
 * @return TRUE if the list of creation options is compatible with the Create()
2158
 *         and CreateCopy() method of the driver, FALSE otherwise.
2159
 */
2160

2161
int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
29,948✔
2162
                                            CSLConstList papszCreationOptions)
2163
{
2164
    VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
29,948✔
2165
    const char *pszOptionList =
2166
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
29,948✔
2167
            GDAL_DMD_CREATIONOPTIONLIST);
29,948✔
2168
    CPLString osDriver;
29,948✔
2169
    osDriver.Printf("driver %s",
2170
                    GDALDriver::FromHandle(hDriver)->GetDescription());
29,948✔
2171
    bool bFoundOptionToRemove = false;
29,948✔
2172
    constexpr const char *const apszExcludedOptions[] = {
29,948✔
2173
        "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2174
    for (const char *pszCO : cpl::Iterate(papszCreationOptions))
42,853✔
2175
    {
2176
        for (const char *pszExcludedOptions : apszExcludedOptions)
65,139✔
2177
        {
2178
            if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
52,234✔
2179
                pszCO[strlen(pszExcludedOptions)] == '=')
191✔
2180
            {
2181
                bFoundOptionToRemove = true;
191✔
2182
                break;
191✔
2183
            }
2184
        }
2185
        if (bFoundOptionToRemove)
13,096✔
2186
            break;
191✔
2187
    }
2188
    CSLConstList papszOptionsToValidate = papszCreationOptions;
29,948✔
2189
    char **papszOptionsToFree = nullptr;
29,948✔
2190
    if (bFoundOptionToRemove)
29,948✔
2191
    {
2192
        for (const char *pszCO : cpl::Iterate(papszCreationOptions))
579✔
2193
        {
2194
            bool bMatch = false;
388✔
2195
            for (const char *pszExcludedOptions : apszExcludedOptions)
1,579✔
2196
            {
2197
                if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
1,395✔
2198
                    pszCO[strlen(pszExcludedOptions)] == '=')
204✔
2199
                {
2200
                    bMatch = true;
204✔
2201
                    break;
204✔
2202
                }
2203
            }
2204
            if (!bMatch)
388✔
2205
                papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
184✔
2206
        }
2207
        papszOptionsToValidate = papszOptionsToFree;
191✔
2208
    }
2209

2210
    const bool bRet = CPL_TO_BOOL(GDALValidateOptions(
29,948✔
2211
        pszOptionList, papszOptionsToValidate, "creation option", osDriver));
2212
    CSLDestroy(papszOptionsToFree);
29,948✔
2213
    return bRet;
29,948✔
2214
}
2215

2216
/************************************************************************/
2217
/*                     GDALValidateOpenOptions()                        */
2218
/************************************************************************/
2219

2220
int GDALValidateOpenOptions(GDALDriverH hDriver,
50,442✔
2221
                            const char *const *papszOpenOptions)
2222
{
2223
    VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
50,442✔
2224
    const char *pszOptionList =
2225
        GDALDriver::FromHandle(hDriver)->GetMetadataItem(
50,442✔
2226
            GDAL_DMD_OPENOPTIONLIST);
50,417✔
2227
    CPLString osDriver;
100,822✔
2228
    osDriver.Printf("driver %s",
2229
                    GDALDriver::FromHandle(hDriver)->GetDescription());
50,410✔
2230
    return GDALValidateOptions(pszOptionList, papszOpenOptions, "open option",
50,403✔
2231
                               osDriver);
50,385✔
2232
}
2233

2234
/************************************************************************/
2235
/*                           GDALValidateOptions()                      */
2236
/************************************************************************/
2237

2238
int GDALValidateOptions(const char *pszOptionList,
89,125✔
2239
                        const char *const *papszOptionsToValidate,
2240
                        const char *pszErrorMessageOptionType,
2241
                        const char *pszErrorMessageContainerName)
2242
{
2243
    if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
89,125✔
2244
        return TRUE;
77,125✔
2245
    if (pszOptionList == nullptr)
12,000✔
2246
        return TRUE;
125✔
2247

2248
    CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
11,875✔
2249
    if (psNode == nullptr)
11,875✔
2250
    {
2251
        CPLError(CE_Warning, CPLE_AppDefined,
×
2252
                 "Could not parse %s list of %s. Assuming options are valid.",
2253
                 pszErrorMessageOptionType, pszErrorMessageContainerName);
2254
        return TRUE;
×
2255
    }
2256

2257
    bool bRet = true;
11,875✔
2258
    while (*papszOptionsToValidate)
32,250✔
2259
    {
2260
        char *pszKey = nullptr;
20,375✔
2261
        const char *pszValue =
2262
            CPLParseNameValue(*papszOptionsToValidate, &pszKey);
20,375✔
2263
        if (pszKey == nullptr)
20,375✔
2264
        {
2265
            CPLError(CE_Warning, CPLE_NotSupported,
1✔
2266
                     "%s '%s' is not formatted with the key=value format",
2267
                     pszErrorMessageOptionType, *papszOptionsToValidate);
2268
            bRet = false;
1✔
2269

2270
            ++papszOptionsToValidate;
1✔
2271
            continue;
665✔
2272
        }
2273

2274
        if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
20,374✔
2275
        {
2276
            ++papszOptionsToValidate;
×
2277
            CPLFree(pszKey);
×
2278
            continue;
×
2279
        }
2280

2281
        // Must we be forgiving in case of missing option ?
2282
        bool bWarnIfMissingKey = true;
20,374✔
2283
        if (pszKey[0] == '@')
20,374✔
2284
        {
2285
            bWarnIfMissingKey = false;
656✔
2286
            memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
656✔
2287
        }
2288

2289
        CPLXMLNode *psChildNode = psNode->psChild;
20,374✔
2290
        while (psChildNode)
168,753✔
2291
        {
2292
            if (EQUAL(psChildNode->pszValue, "OPTION"))
168,089✔
2293
            {
2294
                const char *pszOptionName =
2295
                    CPLGetXMLValue(psChildNode, "name", "");
168,089✔
2296
                /* For option names terminated by wildcard (NITF BLOCKA option
2297
                 * names for example) */
2298
                if (strlen(pszOptionName) > 0 &&
168,089✔
2299
                    pszOptionName[strlen(pszOptionName) - 1] == '*' &&
168,089✔
2300
                    EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
373✔
2301
                {
2302
                    break;
216✔
2303
                }
2304

2305
                /* For option names beginning by a wildcard */
2306
                if (pszOptionName[0] == '*' &&
167,873✔
2307
                    strlen(pszKey) > strlen(pszOptionName) &&
57✔
2308
                    EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
9✔
2309
                          pszOptionName + 1))
2310
                {
2311
                    break;
2✔
2312
                }
2313

2314
                // For options names with * in the middle
2315
                const char *pszStarInOptionName = strchr(pszOptionName, '*');
167,871✔
2316
                if (pszStarInOptionName &&
167,871✔
2317
                    pszStarInOptionName != pszOptionName &&
178✔
2318
                    pszStarInOptionName !=
2319
                        pszOptionName + strlen(pszOptionName) - 1 &&
178✔
2320
                    strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
21✔
2321
                                                         pszOptionName) &&
12✔
2322
                    EQUALN(pszKey, pszOptionName,
12✔
2323
                           static_cast<size_t>(pszStarInOptionName -
2324
                                               pszOptionName)) &&
12✔
2325
                    EQUAL(pszKey +
12✔
2326
                              static_cast<size_t>(pszStarInOptionName -
2327
                                                  pszOptionName) +
2328
                              1,
2329
                          pszStarInOptionName + 1))
2330
                {
2331
                    break;
6✔
2332
                }
2333

2334
                if (EQUAL(pszOptionName, pszKey))
167,865✔
2335
                {
2336
                    break;
19,481✔
2337
                }
2338
                const char *pszAlias = CPLGetXMLValue(
148,384✔
2339
                    psChildNode, "alias",
2340
                    CPLGetXMLValue(psChildNode, "deprecated_alias", ""));
2341
                if (EQUAL(pszAlias, pszKey))
148,384✔
2342
                {
2343
                    CPLDebug("GDAL",
5✔
2344
                             "Using deprecated alias '%s'. New name is '%s'",
2345
                             pszAlias, pszOptionName);
2346
                    break;
5✔
2347
                }
2348
            }
2349
            psChildNode = psChildNode->psNext;
148,379✔
2350
        }
2351
        if (psChildNode == nullptr)
20,374✔
2352
        {
2353
            if (bWarnIfMissingKey &&
678✔
2354
                (!EQUAL(pszErrorMessageOptionType, "open option") ||
14✔
2355
                 CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
×
2356
                              true)))
2357
            {
2358
                CPLError(CE_Warning, CPLE_NotSupported,
14✔
2359
                         "%s does not support %s %s",
2360
                         pszErrorMessageContainerName,
2361
                         pszErrorMessageOptionType, pszKey);
2362
                bRet = false;
14✔
2363
            }
2364

2365
            CPLFree(pszKey);
664✔
2366
            ++papszOptionsToValidate;
664✔
2367
            continue;
664✔
2368
        }
2369

2370
#ifdef DEBUG
2371
        CPLXMLNode *psChildSubNode = psChildNode->psChild;
19,710✔
2372
        while (psChildSubNode)
121,044✔
2373
        {
2374
            if (psChildSubNode->eType == CXT_Attribute)
101,334✔
2375
            {
2376
                if (!(EQUAL(psChildSubNode->pszValue, "name") ||
69,620✔
2377
                      EQUAL(psChildSubNode->pszValue, "alias") ||
49,910✔
2378
                      EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
49,877✔
2379
                      EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
49,797✔
2380
                      EQUAL(psChildSubNode->pszValue, "description") ||
49,764✔
2381
                      EQUAL(psChildSubNode->pszValue, "type") ||
32,858✔
2382
                      EQUAL(psChildSubNode->pszValue, "min") ||
13,148✔
2383
                      EQUAL(psChildSubNode->pszValue, "max") ||
12,890✔
2384
                      EQUAL(psChildSubNode->pszValue, "default") ||
12,560✔
2385
                      EQUAL(psChildSubNode->pszValue, "maxsize") ||
997✔
2386
                      EQUAL(psChildSubNode->pszValue, "required") ||
972✔
2387
                      EQUAL(psChildSubNode->pszValue, "scope")))
917✔
2388
                {
2389
                    /* Driver error */
2390
                    CPLError(CE_Warning, CPLE_NotSupported,
×
2391
                             "%s : unhandled attribute '%s' for %s %s.",
2392
                             pszErrorMessageContainerName,
2393
                             psChildSubNode->pszValue, pszKey,
2394
                             pszErrorMessageOptionType);
2395
                }
2396
            }
2397
            psChildSubNode = psChildSubNode->psNext;
101,334✔
2398
        }
2399
#endif
2400

2401
        const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
19,710✔
2402
        const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
19,710✔
2403
        const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
19,710✔
2404
        if (pszType != nullptr)
19,710✔
2405
        {
2406
            if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
19,710✔
2407
            {
2408
                const char *pszValueIter = pszValue;
8,431✔
2409
                while (*pszValueIter)
21,450✔
2410
                {
2411
                    if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
13,021✔
2412
                          *pszValueIter == '+' || *pszValueIter == '-'))
19✔
2413
                    {
2414
                        CPLError(CE_Warning, CPLE_NotSupported,
2✔
2415
                                 "'%s' is an unexpected value for %s %s of "
2416
                                 "type int.",
2417
                                 pszValue, pszKey, pszErrorMessageOptionType);
2418
                        bRet = false;
2✔
2419
                        break;
2✔
2420
                    }
2421
                    ++pszValueIter;
13,019✔
2422
                }
2423
                if (*pszValueIter == '\0')
8,431✔
2424
                {
2425
                    if (pszMin && atoi(pszValue) < atoi(pszMin))
8,429✔
2426
                    {
2427
                        CPLError(CE_Warning, CPLE_NotSupported,
10✔
2428
                                 "'%s' is an unexpected value for %s %s that "
2429
                                 "should be >= %s.",
2430
                                 pszValue, pszKey, pszErrorMessageOptionType,
2431
                                 pszMin);
2432
                        bRet = false;
10✔
2433
                    }
2434
                    if (pszMax && atoi(pszValue) > atoi(pszMax))
8,429✔
2435
                    {
2436
                        CPLError(CE_Warning, CPLE_NotSupported,
12✔
2437
                                 "'%s' is an unexpected value for %s %s that "
2438
                                 "should be <= %s.",
2439
                                 pszValue, pszKey, pszErrorMessageOptionType,
2440
                                 pszMax);
2441
                        bRet = false;
12✔
2442
                    }
2443
                }
8,431✔
2444
            }
2445
            else if (EQUAL(pszType, "UNSIGNED INT"))
11,279✔
2446
            {
2447
                const char *pszValueIter = pszValue;
3✔
2448
                while (*pszValueIter)
10✔
2449
                {
2450
                    if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
7✔
2451
                          *pszValueIter == '+'))
×
2452
                    {
2453
                        CPLError(CE_Warning, CPLE_NotSupported,
×
2454
                                 "'%s' is an unexpected value for %s %s of "
2455
                                 "type unsigned int.",
2456
                                 pszValue, pszKey, pszErrorMessageOptionType);
2457
                        bRet = false;
×
2458
                        break;
×
2459
                    }
2460
                    ++pszValueIter;
7✔
2461
                }
2462
                if (*pszValueIter == '\0')
3✔
2463
                {
2464
                    if (pszMin && atoi(pszValue) < atoi(pszMin))
3✔
2465
                    {
2466
                        CPLError(CE_Warning, CPLE_NotSupported,
×
2467
                                 "'%s' is an unexpected value for %s %s that "
2468
                                 "should be >= %s.",
2469
                                 pszValue, pszKey, pszErrorMessageOptionType,
2470
                                 pszMin);
2471
                        bRet = false;
×
2472
                    }
2473
                    if (pszMax && atoi(pszValue) > atoi(pszMax))
3✔
2474
                    {
2475
                        CPLError(CE_Warning, CPLE_NotSupported,
×
2476
                                 "'%s' is an unexpected value for %s %s that "
2477
                                 "should be <= %s.",
2478
                                 pszValue, pszKey, pszErrorMessageOptionType,
2479
                                 pszMax);
2480
                        bRet = false;
×
2481
                    }
2482
                }
2483
            }
2484
            else if (EQUAL(pszType, "FLOAT"))
11,276✔
2485
            {
2486
                char *endPtr = nullptr;
574✔
2487
                double dfVal = CPLStrtod(pszValue, &endPtr);
574✔
2488
                if (!(endPtr == nullptr || *endPtr == '\0'))
574✔
2489
                {
2490
                    CPLError(
×
2491
                        CE_Warning, CPLE_NotSupported,
2492
                        "'%s' is an unexpected value for %s %s of type float.",
2493
                        pszValue, pszKey, pszErrorMessageOptionType);
2494
                    bRet = false;
×
2495
                }
2496
                else
2497
                {
2498
                    if (pszMin && dfVal < CPLAtof(pszMin))
574✔
2499
                    {
2500
                        CPLError(CE_Warning, CPLE_NotSupported,
2✔
2501
                                 "'%s' is an unexpected value for %s %s that "
2502
                                 "should be >= %s.",
2503
                                 pszValue, pszKey, pszErrorMessageOptionType,
2504
                                 pszMin);
2505
                        bRet = false;
2✔
2506
                    }
2507
                    if (pszMax && dfVal > CPLAtof(pszMax))
574✔
2508
                    {
2509
                        CPLError(CE_Warning, CPLE_NotSupported,
×
2510
                                 "'%s' is an unexpected value for %s %s that "
2511
                                 "should be <= %s.",
2512
                                 pszValue, pszKey, pszErrorMessageOptionType,
2513
                                 pszMax);
2514
                        bRet = false;
×
2515
                    }
2516
                }
2517
            }
2518
            else if (EQUAL(pszType, "BOOLEAN"))
10,702✔
2519
            {
2520
                if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2,474✔
2521
                      EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2,428✔
2522
                      EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
443✔
2523
                {
2524
                    CPLError(CE_Warning, CPLE_NotSupported,
×
2525
                             "'%s' is an unexpected value for %s %s of type "
2526
                             "boolean.",
2527
                             pszValue, pszKey, pszErrorMessageOptionType);
2528
                    bRet = false;
×
2529
                }
2530
            }
2531
            else if (EQUAL(pszType, "STRING-SELECT"))
8,228✔
2532
            {
2533
                bool bMatchFound = false;
4,919✔
2534
                CPLXMLNode *psStringSelect = psChildNode->psChild;
4,919✔
2535
                while (psStringSelect)
32,495✔
2536
                {
2537
                    if (psStringSelect->eType == CXT_Element &&
32,460✔
2538
                        EQUAL(psStringSelect->pszValue, "Value"))
16,698✔
2539
                    {
2540
                        CPLXMLNode *psOptionNode = psStringSelect->psChild;
16,698✔
2541
                        while (psOptionNode)
28,812✔
2542
                        {
2543
                            if (psOptionNode->eType == CXT_Text &&
16,998✔
2544
                                EQUAL(psOptionNode->pszValue, pszValue))
16,688✔
2545
                            {
2546
                                bMatchFound = true;
4,874✔
2547
                                break;
4,874✔
2548
                            }
2549
                            if (psOptionNode->eType == CXT_Attribute &&
12,124✔
2550
                                (EQUAL(psOptionNode->pszValue, "alias") ||
310✔
2551
                                 EQUAL(psOptionNode->pszValue,
15✔
2552
                                       "deprecated_alias")) &&
295✔
2553
                                EQUAL(psOptionNode->psChild->pszValue,
295✔
2554
                                      pszValue))
2555
                            {
2556
                                bMatchFound = true;
10✔
2557
                                break;
10✔
2558
                            }
2559
                            psOptionNode = psOptionNode->psNext;
12,114✔
2560
                        }
2561
                        if (bMatchFound)
16,698✔
2562
                            break;
4,884✔
2563
                    }
2564
                    psStringSelect = psStringSelect->psNext;
27,576✔
2565
                }
2566
                if (!bMatchFound)
4,919✔
2567
                {
2568
                    CPLError(CE_Warning, CPLE_NotSupported,
35✔
2569
                             "'%s' is an unexpected value for %s %s of type "
2570
                             "string-select.",
2571
                             pszValue, pszKey, pszErrorMessageOptionType);
2572
                    bRet = false;
35✔
2573
                }
2574
            }
2575
            else if (EQUAL(pszType, "STRING"))
3,309✔
2576
            {
2577
                const char *pszMaxSize =
2578
                    CPLGetXMLValue(psChildNode, "maxsize", nullptr);
3,309✔
2579
                if (pszMaxSize != nullptr)
3,309✔
2580
                {
2581
                    if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
25✔
2582
                    {
2583
                        CPLError(CE_Warning, CPLE_NotSupported,
1✔
2584
                                 "'%s' is of size %d, whereas maximum size for "
2585
                                 "%s %s is %d.",
2586
                                 pszValue, static_cast<int>(strlen(pszValue)),
1✔
2587
                                 pszKey, pszErrorMessageOptionType,
2588
                                 atoi(pszMaxSize));
2589
                        bRet = false;
1✔
2590
                    }
2591
                }
2592
            }
2593
            else
2594
            {
2595
                /* Driver error */
2596
                CPLError(CE_Warning, CPLE_NotSupported,
×
2597
                         "%s : type '%s' for %s %s is not recognized.",
2598
                         pszErrorMessageContainerName, pszType, pszKey,
2599
                         pszErrorMessageOptionType);
2600
            }
2601
        }
2602
        else
2603
        {
2604
            /* Driver error */
2605
            CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
×
2606
                     pszErrorMessageContainerName, pszKey,
2607
                     pszErrorMessageOptionType);
2608
        }
2609
        CPLFree(pszKey);
19,710✔
2610
        ++papszOptionsToValidate;
19,710✔
2611
    }
2612

2613
    CPLDestroyXMLNode(psNode);
11,875✔
2614
    return bRet ? TRUE : FALSE;
11,875✔
2615
}
2616

2617
/************************************************************************/
2618
/*                         GDALIdentifyDriver()                         */
2619
/************************************************************************/
2620

2621
/**
2622
 * \brief Identify the driver that can open a dataset.
2623
 *
2624
 * This function will try to identify the driver that can open the passed file
2625
 * name by invoking the Identify method of each registered GDALDriver in turn.
2626
 * The first driver that successfully identifies the file name will be returned.
2627
 * If all drivers fail then NULL is returned.
2628
 *
2629
 * In order to reduce the need for such searches to touch the operating system
2630
 * file system machinery, it is possible to give an optional list of files.
2631
 * This is the list of all files at the same level in the file system as the
2632
 * target file, including the target file. The filenames will not include any
2633
 * path components, and are essentially just the output of VSIReadDir() on the
2634
 * parent directory. If the target object does not have filesystem semantics
2635
 * then the file list should be NULL.
2636
 *
2637
 * @param pszFilename the name of the file to access.  In the case of
2638
 * exotic drivers this may not refer to a physical file, but instead contain
2639
 * information for the driver on how to access a dataset.
2640
 *
2641
 * @param papszFileList an array of strings, whose last element is the NULL
2642
 * pointer.  These strings are filenames that are auxiliary to the main
2643
 * filename. The passed value may be NULL.
2644
 *
2645
 * @return A GDALDriverH handle or NULL on failure.  For C++ applications
2646
 * this handle can be cast to a GDALDriver *.
2647
 */
2648

2649
GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
20,798✔
2650
                                           CSLConstList papszFileList)
2651

2652
{
2653
    return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
20,798✔
2654
}
2655

2656
/************************************************************************/
2657
/*                         GDALIdentifyDriverEx()                       */
2658
/************************************************************************/
2659

2660
/**
2661
 * \brief Identify the driver that can open a dataset.
2662
 *
2663
 * This function will try to identify the driver that can open the passed file
2664
 * name by invoking the Identify method of each registered GDALDriver in turn.
2665
 * The first driver that successfully identifies the file name will be returned.
2666
 * If all drivers fail then NULL is returned.
2667
 *
2668
 * In order to reduce the need for such searches to touch the operating system
2669
 * file system machinery, it is possible to give an optional list of files.
2670
 * This is the list of all files at the same level in the file system as the
2671
 * target file, including the target file. The filenames will not include any
2672
 * path components, and are essentially just the output of VSIReadDir() on the
2673
 * parent directory. If the target object does not have filesystem semantics
2674
 * then the file list should be NULL.
2675
 *
2676
 * @param pszFilename the name of the file to access.  In the case of
2677
 * exotic drivers this may not refer to a physical file, but instead contain
2678
 * information for the driver on how to access a dataset.
2679
 *
2680
 * @param nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2681
 * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2682
 * both kinds are implied.
2683
 *
2684
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2685
 * terminated list of strings with the driver short names that must be
2686
 * considered.
2687
 *
2688
 * @param papszFileList an array of strings, whose last element is the NULL
2689
 * pointer.  These strings are filenames that are auxiliary to the main
2690
 * filename. The passed value may be NULL.
2691
 *
2692
 * @return A GDALDriverH handle or NULL on failure.  For C++ applications
2693
 * this handle can be cast to a GDALDriver *.
2694
 *
2695
 * @since GDAL 2.2
2696
 */
2697

2698
GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
20,888✔
2699
    const char *pszFilename, unsigned int nIdentifyFlags,
2700
    const char *const *papszAllowedDrivers, const char *const *papszFileList)
2701
{
2702
    GDALDriverManager *poDM = GetGDALDriverManager();
20,888✔
2703
    CPLAssert(nullptr != poDM);
20,888✔
2704

2705
    // If no driver kind is specified, assume all are to be probed.
2706
    if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
20,888✔
2707
        nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
20,845✔
2708

2709
    GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
41,776✔
2710
    oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
20,888✔
2711

2712
    CPLErrorStateBackuper oBackuper;
41,776✔
2713
    CPLErrorSetState(CE_None, CPLE_AppDefined, "");
20,888✔
2714

2715
    const int nDriverCount = poDM->GetDriverCount();
20,888✔
2716

2717
    // First pass: only use drivers that have a pfnIdentify implementation.
2718
    std::vector<GDALDriver *> apoSecondPassDrivers;
41,776✔
2719
    for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
4,437,260✔
2720
    {
2721
        GDALDriver *poDriver = poDM->GetDriver(iDriver);
4,417,520✔
2722
        if (papszAllowedDrivers != nullptr &&
4,424,700✔
2723
            CSLFindString(papszAllowedDrivers,
7,183✔
2724
                          GDALGetDriverShortName(poDriver)) == -1)
2725
        {
2726
            continue;
851,115✔
2727
        }
2728

2729
        VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
4,411,530✔
2730

2731
        if (poDriver->pfnIdentify == nullptr &&
4,410,380✔
2732
            poDriver->pfnIdentifyEx == nullptr)
840,221✔
2733
        {
2734
            continue;
840,221✔
2735
        }
2736

2737
        if (papszAllowedDrivers != nullptr &&
3,570,200✔
2738
            CSLFindString(papszAllowedDrivers,
44✔
2739
                          GDALGetDriverShortName(poDriver)) == -1)
2740
            continue;
×
2741
        if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
10,705,900✔
2742
            (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
3,570,660✔
2743
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
496✔
2744
            continue;
141✔
2745
        if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
10,713,300✔
2746
            (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
3,574,780✔
2747
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4,761✔
2748
            continue;
3,614✔
2749

2750
        if (poDriver->pfnIdentifyEx)
3,566,400✔
2751
        {
2752
            if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
×
2753
                return poDriver;
×
2754
        }
2755
        else
2756
        {
2757
            const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
3,566,400✔
2758
            if (nIdentifyRes > 0)
3,566,400✔
2759
                return poDriver;
1,151✔
2760
            if (nIdentifyRes < 0 &&
3,585,130✔
2761
                poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
19,880✔
2762
            {
2763
                // Not loaded plugin
2764
                apoSecondPassDrivers.push_back(poDriver);
15✔
2765
            }
2766
        }
2767
    }
2768

2769
    // second pass: try loading plugin drivers
2770
    for (auto poDriver : apoSecondPassDrivers)
19,749✔
2771
    {
2772
        // Force plugin driver loading
2773
        poDriver->GetMetadata();
13✔
2774
        if (poDriver->pfnIdentify(&oOpenInfo) > 0)
13✔
2775
            return poDriver;
1✔
2776
    }
2777

2778
    // third pass: slow method.
2779
    for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
4,351,460✔
2780
    {
2781
        GDALDriver *poDriver = poDM->GetDriver(iDriver);
4,331,770✔
2782
        if (papszAllowedDrivers != nullptr &&
4,335,510✔
2783
            CSLFindString(papszAllowedDrivers,
3,739✔
2784
                          GDALGetDriverShortName(poDriver)) == -1)
2785
        {
2786
            continue;
3,722✔
2787
        }
2788

2789
        VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
4,328,050✔
2790

2791
        if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
12,982,700✔
2792
            (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
4,328,490✔
2793
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
438✔
2794
            continue;
139✔
2795
        if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
12,984,400✔
2796
            (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
4,329,440✔
2797
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
1,535✔
2798
            continue;
925✔
2799

2800
        if (poDriver->pfnIdentifyEx != nullptr)
4,326,980✔
2801
        {
2802
            if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
×
2803
                continue;
×
2804
        }
2805
        else if (poDriver->pfnIdentify != nullptr)
4,326,980✔
2806
        {
2807
            if (poDriver->pfnIdentify(&oOpenInfo) == 0)
3,502,240✔
2808
                continue;
3,482,490✔
2809
        }
2810

2811
        GDALDataset *poDS;
2812
        if (poDriver->pfnOpen != nullptr)
844,490✔
2813
        {
2814
            poDS = poDriver->pfnOpen(&oOpenInfo);
805,132✔
2815
            if (poDS != nullptr)
805,132✔
2816
            {
2817
                delete poDS;
47✔
2818
                return GDALDriver::ToHandle(poDriver);
47✔
2819
            }
2820

2821
            if (CPLGetLastErrorType() != CE_None)
805,085✔
2822
                return nullptr;
×
2823
        }
2824
        else if (poDriver->pfnOpenWithDriverArg != nullptr)
39,358✔
2825
        {
2826
            poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
×
2827
            if (poDS != nullptr)
×
2828
            {
2829
                delete poDS;
×
2830
                return GDALDriver::ToHandle(poDriver);
×
2831
            }
2832

2833
            if (CPLGetLastErrorType() != CE_None)
×
2834
                return nullptr;
×
2835
        }
2836
    }
2837

2838
    return nullptr;
19,689✔
2839
}
2840

2841
/************************************************************************/
2842
/*                          SetMetadataItem()                           */
2843
/************************************************************************/
2844

2845
CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
3,279,700✔
2846
                                   const char *pszDomain)
2847

2848
{
2849
    if (pszDomain == nullptr || pszDomain[0] == '\0')
3,279,700✔
2850
    {
2851
        /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
2852
        if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
3,422,010✔
2853
            GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
146,427✔
2854
        {
2855
            GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
146,427✔
2856
        }
2857
        /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
2858
        else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
6,315,720✔
2859
                 strchr(pszValue, ' ') == nullptr &&
3,133,260✔
2860
                 GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
4,106✔
2861
                     nullptr)
2862
        {
2863
            GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
4,106✔
2864
        }
2865
    }
2866
    return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
3,279,700✔
2867
}
2868

2869
/************************************************************************/
2870
/*                   DoesDriverHandleExtension()                        */
2871
/************************************************************************/
2872

2873
static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
152,556✔
2874
{
2875
    bool bRet = false;
152,556✔
2876
    const char *pszDriverExtensions =
2877
        GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
152,556✔
2878
    if (pszDriverExtensions)
152,556✔
2879
    {
2880
        const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
252,086✔
2881
        const int nTokens = aosTokens.size();
126,043✔
2882
        for (int j = 0; j < nTokens; ++j)
282,835✔
2883
        {
2884
            if (EQUAL(pszExt, aosTokens[j]))
160,819✔
2885
            {
2886
                bRet = true;
4,027✔
2887
                break;
4,027✔
2888
            }
2889
        }
2890
    }
2891
    return bRet;
152,556✔
2892
}
2893

2894
/************************************************************************/
2895
/*                  GDALGetOutputDriversForDatasetName()                */
2896
/************************************************************************/
2897

2898
/** Return a list of driver short names that are likely candidates for the
2899
 * provided output file name.
2900
 *
2901
 * @param pszDestDataset Output dataset name (might not exist).
2902
 * @param nFlagRasterVector GDAL_OF_RASTER, GDAL_OF_VECTOR or
2903
 *                          binary-or'ed combination of both
2904
 * @param bSingleMatch Whether a single match is desired, that is to say the
2905
 *                     returned list will contain at most one item, which will
2906
 *                     be the first driver in the order they are registered to
2907
 *                     match the output dataset name. Note that in this mode, if
2908
 *                     nFlagRasterVector==GDAL_OF_RASTER and pszDestDataset has
2909
 *                     no extension, GTiff will be selected.
2910
 * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
2911
 *                     true and there are more than 2 candidates.
2912
 * @return NULL terminated list of driver short names.
2913
 * To be freed with CSLDestroy()
2914
 * @since 3.9
2915
 */
2916
char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
2,320✔
2917
                                          int nFlagRasterVector,
2918
                                          bool bSingleMatch, bool bEmitWarning)
2919
{
2920
    CPLStringList aosDriverNames;
4,640✔
2921

2922
    std::string osExt = CPLGetExtensionSafe(pszDestDataset);
4,640✔
2923
    if (EQUAL(osExt.c_str(), "zip"))
2,320✔
2924
    {
2925
        const CPLString osLower(CPLString(pszDestDataset).tolower());
2✔
2926
        if (osLower.endsWith(".shp.zip"))
1✔
2927
        {
2928
            osExt = "shp.zip";
1✔
2929
        }
2930
        else if (osLower.endsWith(".gpkg.zip"))
×
2931
        {
2932
            osExt = "gpkg.zip";
×
2933
        }
2934
    }
2935

2936
    const int nDriverCount = GDALGetDriverCount();
2,320✔
2937
    for (int i = 0; i < nDriverCount; i++)
512,315✔
2938
    {
2939
        GDALDriverH hDriver = GDALGetDriver(i);
509,995✔
2940
        bool bOk = false;
509,995✔
2941
        if ((GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
509,995✔
2942
                 nullptr ||
310,477✔
2943
             GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, nullptr) !=
310,477✔
2944
                 nullptr) &&
1,019,990✔
2945
            (((nFlagRasterVector & GDAL_OF_RASTER) &&
259,838✔
2946
              GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER, nullptr) !=
215,823✔
2947
                  nullptr) ||
126,876✔
2948
             ((nFlagRasterVector & GDAL_OF_VECTOR) &&
126,876✔
2949
              GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr) !=
44,015✔
2950
                  nullptr)))
2951
        {
2952
            bOk = true;
154,969✔
2953
        }
2954
        else if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR_TRANSLATE_FROM,
355,026✔
2955
                                     nullptr) &&
356,953✔
2956
                 (nFlagRasterVector & GDAL_OF_VECTOR) != 0)
1,927✔
2957
        {
2958
            bOk = true;
×
2959
        }
2960
        if (bOk)
509,995✔
2961
        {
2962
            if (!osExt.empty() &&
307,525✔
2963
                DoesDriverHandleExtension(hDriver, osExt.c_str()))
152,556✔
2964
            {
2965
                aosDriverNames.AddString(GDALGetDriverShortName(hDriver));
4,027✔
2966
            }
2967
            else
2968
            {
2969
                const char *pszPrefix = GDALGetMetadataItem(
150,942✔
2970
                    hDriver, GDAL_DMD_CONNECTION_PREFIX, nullptr);
2971
                if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
150,942✔
2972
                {
2973
                    aosDriverNames.AddString(GDALGetDriverShortName(hDriver));
9✔
2974
                }
2975
            }
2976
        }
2977
    }
2978

2979
    // GMT is registered before netCDF for opening reasons, but we want
2980
    // netCDF to be used by default for output.
2981
    if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
2,322✔
2982
        EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
2,322✔
2983
    {
2984
        aosDriverNames.Clear();
×
2985
        aosDriverNames.AddString("netCDF");
×
2986
        aosDriverNames.AddString("GMT");
×
2987
    }
2988

2989
    if (bSingleMatch)
2,320✔
2990
    {
2991
        if (nFlagRasterVector == GDAL_OF_RASTER)
1,927✔
2992
        {
2993
            if (aosDriverNames.empty())
1,927✔
2994
            {
2995
                if (osExt.empty())
10✔
2996
                {
2997
                    aosDriverNames.AddString("GTiff");
9✔
2998
                }
2999
            }
3000
            else if (aosDriverNames.size() >= 2)
1,917✔
3001
            {
3002
                if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3,496✔
3003
                                      EQUAL(aosDriverNames[1], "COG")))
1,748✔
3004
                {
3005
                    CPLError(CE_Warning, CPLE_AppDefined,
×
3006
                             "Several drivers matching %s extension. Using %s",
3007
                             osExt.c_str(), aosDriverNames[0]);
3008
                }
3009
                const std::string osDrvName = aosDriverNames[0];
3,496✔
3010
                aosDriverNames.Clear();
1,748✔
3011
                aosDriverNames.AddString(osDrvName.c_str());
1,748✔
3012
            }
3013
        }
3014
        else if (aosDriverNames.size() >= 2)
×
3015
        {
3016
            if (bEmitWarning)
×
3017
            {
3018
                CPLError(CE_Warning, CPLE_AppDefined,
×
3019
                         "Several drivers matching %s extension. Using %s",
3020
                         osExt.c_str(), aosDriverNames[0]);
3021
            }
3022
            const std::string osDrvName = aosDriverNames[0];
×
3023
            aosDriverNames.Clear();
×
3024
            aosDriverNames.AddString(osDrvName.c_str());
×
3025
        }
3026
    }
3027

3028
    return aosDriverNames.StealList();
4,640✔
3029
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc