Coverage Report

Created: 2026-04-01 06:20

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