LCOV - code coverage report
Current view: top level - gcore - gdaldriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1042 1203 86.6 %
Date: 2025-09-10 17:48:50 Functions: 47 51 92.2 %

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

Generated by: LCOV version 1.14