LCOV - code coverage report
Current view: top level - gcore - gdaldriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1100 1273 86.4 %
Date: 2026-06-27 16:33:51 Functions: 49 53 92.5 %

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

Generated by: LCOV version 1.14