LCOV - code coverage report
Current view: top level - gcore - gdaldriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 940 1082 86.9 %
Date: 2025-01-18 12:42:00 Functions: 39 42 92.9 %

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

Generated by: LCOV version 1.14