LCOV - code coverage report
Current view: top level - gcore - gdaldriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1010 1173 86.1 %
Date: 2025-07-08 21:33:46 Functions: 45 49 91.8 %

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

Generated by: LCOV version 1.14