LCOV - code coverage report
Current view: top level - gcore - gdaldrivermanager.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 468 592 79.1 %
Date: 2026-04-22 14:22:58 Functions: 43 45 95.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Implementation of GDALDriverManager class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, Frank Warmerdam
       9             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gdal_priv.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <cstring>
      19             : #include <map>
      20             : #include <set>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_http.h"
      25             : #include "cpl_multiproc.h"
      26             : #include "cpl_port.h"
      27             : #include "cpl_string.h"
      28             : #include "cpl_vsi.h"
      29             : #include "cpl_compressor.h"
      30             : #include "gdal_alg.h"
      31             : #include "gdal_alg_priv.h"
      32             : #include "gdal.h"
      33             : #include "gdal_pam.h"
      34             : #include "gdalplugindriverproxy.h"
      35             : #include "gdal_version_full/gdal_version.h"
      36             : #include "gdal_thread_pool.h"
      37             : #include "ogr_srs_api.h"
      38             : #include "ograpispy.h"
      39             : #ifdef HAVE_XERCES
      40             : #include "ogr_xerces.h"
      41             : #endif  // HAVE_XERCES
      42             : 
      43             : #ifdef _MSC_VER
      44             : #ifdef MSVC_USE_VLD
      45             : #include <wchar.h>
      46             : #include <vld.h>
      47             : #endif
      48             : #endif
      49             : 
      50             : // FIXME: Disabled following code as it crashed on OSX CI test.
      51             : // #include <mutex>
      52             : 
      53             : /************************************************************************/
      54             : /* ==================================================================== */
      55             : /*                           GDALDriverManager                          */
      56             : /* ==================================================================== */
      57             : /************************************************************************/
      58             : 
      59             : static volatile GDALDriverManager *poDM = nullptr;
      60             : static CPLMutex *hDMMutex = nullptr;
      61             : 
      62             : // FIXME: Disabled following code as it crashed on OSX CI test.
      63             : // static std::mutex oDeleteMutex;
      64             : 
      65          57 : CPLMutex **GDALGetphDMMutex()
      66             : {
      67          57 :     return &hDMMutex;
      68             : }
      69             : 
      70             : /************************************************************************/
      71             : /*                        GetGDALDriverManager()                        */
      72             : /*                                                                      */
      73             : /*      A freestanding function to get the only instance of the         */
      74             : /*      GDALDriverManager.                                              */
      75             : /************************************************************************/
      76             : 
      77             : /**
      78             :  * \brief Fetch the global GDAL driver manager.
      79             :  *
      80             :  * This function fetches the pointer to the singleton global driver manager.
      81             :  * If the driver manager doesn't exist it is automatically created.
      82             :  *
      83             :  * @return pointer to the global driver manager.  This should not be able
      84             :  * to fail.
      85             :  */
      86             : 
      87     1208360 : GDALDriverManager *GetGDALDriverManager()
      88             : 
      89             : {
      90     1208360 :     if (poDM == nullptr)
      91             :     {
      92        3610 :         CPLMutexHolderD(&hDMMutex);
      93             :         // cppcheck-suppress identicalInnerCondition
      94        1805 :         if (poDM == nullptr)
      95        1805 :             poDM = new GDALDriverManager();
      96             :     }
      97             : 
      98     1208360 :     CPLAssert(nullptr != poDM);
      99             : 
     100     1208360 :     return const_cast<GDALDriverManager *>(poDM);
     101             : }
     102             : 
     103             : /************************************************************************/
     104             : /*                         GDALDriverManager()                          */
     105             : /************************************************************************/
     106             : 
     107             : #define XSTRINGIFY(x) #x
     108             : #define STRINGIFY(x) XSTRINGIFY(x)
     109             : 
     110        1805 : GDALDriverManager::GDALDriverManager()
     111             : {
     112        1805 :     CPLAssert(poDM == nullptr);
     113             : 
     114        1805 :     CPLLoadConfigOptionsFromPredefinedFiles();
     115             : 
     116        1805 :     CPLHTTPSetDefaultUserAgent(
     117             :         "GDAL/" STRINGIFY(GDAL_VERSION_MAJOR) "." STRINGIFY(
     118             :             GDAL_VERSION_MINOR) "." STRINGIFY(GDAL_VERSION_REV));
     119             : 
     120             : /* -------------------------------------------------------------------- */
     121             : /*      We want to push a location to search for data files             */
     122             : /*      supporting GDAL/OGR such as EPSG csv files, S-57 definition     */
     123             : /*      files, and so forth.  Use the INST_DATA macro (setup at         */
     124             : /*      configure time) if available. Otherwise we don't push anything  */
     125             : /*      and we hope other mechanisms such as environment variables will */
     126             : /*      have been employed.                                             */
     127             : /* -------------------------------------------------------------------- */
     128             : #ifdef INST_DATA
     129        1805 :     if (CPLGetConfigOption("GDAL_DATA", nullptr) != nullptr)
     130             :     {
     131             :         // This one is picked up automatically by finder initialization.
     132             :     }
     133             :     else
     134             :     {
     135           2 :         CPLPushFinderLocation(INST_DATA);
     136             :     }
     137             : #endif
     138        1805 : }
     139             : 
     140             : /************************************************************************/
     141             : /*                         ~GDALDriverManager()                         */
     142             : /************************************************************************/
     143             : 
     144             : // Keep these two in sync with gdalproxypool.cpp.
     145             : void GDALDatasetPoolPreventDestroy();
     146             : void GDALDatasetPoolForceDestroy();
     147             : 
     148        2272 : GDALDriverManager::~GDALDriverManager()
     149             : 
     150             : {
     151             :     /* -------------------------------------------------------------------- */
     152             :     /*      Cleanup any open datasets.                                      */
     153             :     /* -------------------------------------------------------------------- */
     154             : 
     155             :     // We have to prevent the destroying of the dataset pool during this first
     156             :     // phase, otherwise it cause crashes with a VRT B referencing a VRT A, and
     157             :     // if CloseDependentDatasets() is called first on VRT A.
     158             :     // If we didn't do this nasty trick, due to the refCountOfDisableRefCount
     159             :     // mechanism that cheats the real refcount of the dataset pool, we might
     160             :     // destroy the dataset pool too early, leading the VRT A to
     161             :     // destroy itself indirectly ... Ok, I am aware this explanation does
     162             :     // not make any sense unless you try it under a debugger ...
     163             :     // When people just manipulate "top-level" dataset handles, we luckily
     164             :     // don't need this horrible hack, but GetOpenDatasets() expose "low-level"
     165             :     // datasets, which defeat some "design" of the proxy pool.
     166        1136 :     GDALDatasetPoolPreventDestroy();
     167             : 
     168             :     // First begin by requesting each remaining dataset to drop any reference
     169             :     // to other datasets.
     170        1136 :     bool bHasDroppedRef = false;
     171             : 
     172        1151 :     do
     173             :     {
     174        1151 :         int nDSCount = 0;
     175        1151 :         GDALDataset **papoDSList = GDALDataset::GetOpenDatasets(&nDSCount);
     176             : 
     177             :         // If a dataset has dropped a reference, the list might have become
     178             :         // invalid, so go out of the loop and try again with the new valid
     179             :         // list.
     180        1151 :         bHasDroppedRef = false;
     181        1402 :         for (int i = 0; i < nDSCount && !bHasDroppedRef; ++i)
     182             :         {
     183             : #if DEBUG_VERBOSE
     184             :             CPLDebug("GDAL", "Call CloseDependentDatasets() on %s",
     185             :                      papoDSList[i]->GetDescription());
     186             : #endif  // DEBUG_VERBOSE
     187             :             bHasDroppedRef =
     188         251 :                 CPL_TO_BOOL(papoDSList[i]->CloseDependentDatasets());
     189             :         }
     190             :     } while (bHasDroppedRef);
     191             : 
     192             :     // Now let's destroy the dataset pool. Nobody should use it afterwards
     193             :     // if people have well released their dependent datasets above.
     194        1136 :     GDALDatasetPoolForceDestroy();
     195             : 
     196             :     // Now close the stand-alone datasets.
     197        1136 :     int nDSCount = 0;
     198        1136 :     GDALDataset **papoDSList = GDALDataset::GetOpenDatasets(&nDSCount);
     199        1203 :     for (int i = 0; i < nDSCount; ++i)
     200             :     {
     201          67 :         CPLDebug("GDAL", "Force close of %s (%p) in GDALDriverManager cleanup.",
     202          67 :                  papoDSList[i]->GetDescription(), papoDSList[i]);
     203             :         // Destroy with delete operator rather than GDALClose() to force
     204             :         // deletion of datasets with multiple reference count.
     205             :         // We could also iterate while GetOpenDatasets() returns a non NULL
     206             :         // list.
     207          67 :         delete papoDSList[i];
     208             :     }
     209             : 
     210             :     /* -------------------------------------------------------------------- */
     211             :     /*      Destroy the existing drivers.                                   */
     212             :     /* -------------------------------------------------------------------- */
     213      259004 :     while (GetDriverCount() > 0)
     214             :     {
     215      257868 :         GDALDriver *poDriver = GetDriver(0);
     216             : 
     217      257868 :         DeregisterDriver(poDriver);
     218      257868 :         delete poDriver;
     219             :     }
     220             : 
     221             :     {
     222        1136 :         auto oIter = oMapNameToDrivers.find("MEMORY");
     223        1136 :         if (oIter != oMapNameToDrivers.end())
     224        1136 :             delete oIter->second;
     225             :     }
     226             : 
     227        1136 :     CleanupPythonDrivers();
     228             : 
     229        1136 :     GDALDestroyGlobalThreadPool();
     230             : 
     231             :     /* -------------------------------------------------------------------- */
     232             :     /*      Cleanup local memory.                                           */
     233             :     /* -------------------------------------------------------------------- */
     234        1136 :     VSIFree(papoDrivers);
     235             : 
     236             :     /* -------------------------------------------------------------------- */
     237             :     /*      Cleanup any Proxy related memory.                               */
     238             :     /* -------------------------------------------------------------------- */
     239        1136 :     PamCleanProxyDB();
     240             : 
     241             :     /* -------------------------------------------------------------------- */
     242             :     /*      Cleanup any memory allocated by the OGRSpatialReference         */
     243             :     /*      related subsystem.                                              */
     244             :     /* -------------------------------------------------------------------- */
     245        1136 :     OSRCleanup();
     246             : 
     247             :     /* -------------------------------------------------------------------- */
     248             :     /*      Blow away all the finder hints paths.  We really should not     */
     249             :     /*      be doing all of them, but it is currently hard to keep track    */
     250             :     /*      of those that actually belong to us.                            */
     251             :     /* -------------------------------------------------------------------- */
     252        1136 :     CPLFinderClean();
     253        1136 :     CPLFreeConfig();
     254        1136 :     CPLCleanupSharedFileMutex();
     255             : 
     256             : #ifdef HAVE_XERCES
     257        1136 :     OGRCleanupXercesMutex();
     258             : #endif
     259             : 
     260             : #ifdef OGRAPISPY_ENABLED
     261        1136 :     OGRAPISpyDestroyMutex();
     262             : #endif
     263             : 
     264             :     /* -------------------------------------------------------------------- */
     265             :     /*      Cleanup VSIFileManager.                                         */
     266             :     /* -------------------------------------------------------------------- */
     267        1136 :     VSICleanupFileManager();
     268        1136 :     CPLDestroyCompressorRegistry();
     269             : 
     270             :     /* -------------------------------------------------------------------- */
     271             :     /*      Cleanup thread local storage ... I hope the program is all      */
     272             :     /*      done with GDAL/OGR!                                             */
     273             :     /* -------------------------------------------------------------------- */
     274        1136 :     CPLCleanupTLS();
     275             : 
     276             :     /* -------------------------------------------------------------------- */
     277             :     /*      Cleanup our mutex.                                              */
     278             :     /* -------------------------------------------------------------------- */
     279        1136 :     if (hDMMutex)
     280             :     {
     281        1136 :         CPLDestroyMutex(hDMMutex);
     282        1136 :         hDMMutex = nullptr;
     283             :     }
     284             : 
     285             :     /* -------------------------------------------------------------------- */
     286             :     /*      Cleanup dataset list mutex.                                     */
     287             :     /* -------------------------------------------------------------------- */
     288        1136 :     if (*GDALGetphDLMutex() != nullptr)
     289             :     {
     290        1136 :         CPLDestroyMutex(*GDALGetphDLMutex());
     291        1136 :         *GDALGetphDLMutex() = nullptr;
     292             :     }
     293             : 
     294             :     /* -------------------------------------------------------------------- */
     295             :     /*      Cleanup raster block mutex.                                     */
     296             :     /* -------------------------------------------------------------------- */
     297        1136 :     GDALRasterBlock::DestroyRBMutex();
     298             : 
     299             :     /* -------------------------------------------------------------------- */
     300             :     /*      Cleanup gdaltransformer.cpp mutex.                              */
     301             :     /* -------------------------------------------------------------------- */
     302        1136 :     GDALCleanupTransformDeserializerMutex();
     303             : 
     304             :     /* -------------------------------------------------------------------- */
     305             :     /*      Cleanup cpl_error.cpp mutex.                                    */
     306             :     /* -------------------------------------------------------------------- */
     307        1136 :     CPLCleanupErrorMutex();
     308             : 
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      Cleanup CPLsetlocale mutex.                                     */
     311             :     /* -------------------------------------------------------------------- */
     312        1136 :     CPLCleanupSetlocaleMutex();
     313             : 
     314             :     /* -------------------------------------------------------------------- */
     315             :     /*      Cleanup curl related stuff.                                     */
     316             :     /* -------------------------------------------------------------------- */
     317        1136 :     CPLHTTPCleanup();
     318             : 
     319             :     /* -------------------------------------------------------------------- */
     320             :     /*      Cleanup the master CPL mutex, which governs the creation        */
     321             :     /*      of all other mutexes.                                           */
     322             :     /* -------------------------------------------------------------------- */
     323        1136 :     CPLCleanupMasterMutex();
     324             : 
     325             :     /* -------------------------------------------------------------------- */
     326             :     /*      Ensure the global driver manager pointer is NULLed out.         */
     327             :     /* -------------------------------------------------------------------- */
     328        1136 :     if (poDM == this)
     329        1136 :         poDM = nullptr;
     330        2272 : }
     331             : 
     332             : /************************************************************************/
     333             : /*                           GetDriverCount()                           */
     334             : /************************************************************************/
     335             : 
     336             : /**
     337             :  * \brief Fetch the number of registered drivers.
     338             :  *
     339             :  * This C analog to this is GDALGetDriverCount().
     340             :  *
     341             :  * @return the number of registered drivers.
     342             :  */
     343             : 
     344      295667 : int GDALDriverManager::GetDriverCount() const
     345             : 
     346             : {
     347      295667 :     return nDrivers;
     348             : }
     349             : 
     350             : //! @cond Doxygen_Suppress
     351       85163 : int GDALDriverManager::GetDriverCount(bool bIncludeHidden) const
     352             : 
     353             : {
     354       85163 :     if (!bIncludeHidden)
     355           0 :         return nDrivers;
     356       85163 :     return nDrivers + static_cast<int>(m_aoHiddenDrivers.size());
     357             : }
     358             : 
     359             : //! @endcond
     360             : 
     361             : /************************************************************************/
     362             : /*                           IsKnownDriver()                            */
     363             : /************************************************************************/
     364             : 
     365             : //! @cond Doxygen_Suppress
     366           0 : bool GDALDriverManager::IsKnownDriver(const char *pszDriverName) const
     367             : {
     368           0 :     CPLMutexHolderD(&hDMMutex);
     369           0 :     if (cpl::contains(oMapNameToDrivers, CPLString(pszDriverName).toupper()))
     370           0 :         return true;
     371           0 :     for (const auto &poDriver : m_aoHiddenDrivers)
     372             :     {
     373           0 :         if (EQUAL(poDriver->GetDescription(), pszDriverName))
     374           0 :             return true;
     375             :     }
     376           0 :     return false;
     377             : }
     378             : 
     379             : //! @endcond
     380             : 
     381             : /************************************************************************/
     382             : /*                       GetHiddenDriverByName()                        */
     383             : /************************************************************************/
     384             : 
     385             : //! @cond Doxygen_Suppress
     386           4 : GDALDriver *GDALDriverManager::GetHiddenDriverByName(const char *pszName)
     387             : {
     388           8 :     CPLMutexHolderD(&hDMMutex);
     389           4 :     for (const auto &poDriver : m_aoHiddenDrivers)
     390             :     {
     391           0 :         if (EQUAL(poDriver->GetDescription(), pszName))
     392           0 :             return poDriver.get();
     393             :     }
     394           4 :     return nullptr;
     395             : }
     396             : 
     397             : //! @endcond
     398             : 
     399             : /************************************************************************/
     400             : /*                         GDALGetDriverCount()                         */
     401             : /************************************************************************/
     402             : 
     403             : /**
     404             :  * \brief Fetch the number of registered drivers.
     405             :  *
     406             :  * @see GDALDriverManager::GetDriverCount()
     407             :  */
     408             : 
     409        1474 : int CPL_STDCALL GDALGetDriverCount()
     410             : 
     411             : {
     412        1474 :     return GetGDALDriverManager()->GetDriverCount();
     413             : }
     414             : 
     415             : /************************************************************************/
     416             : /*                             GetDriver()                              */
     417             : /************************************************************************/
     418             : 
     419             : /**
     420             :  * \brief Fetch driver by index.
     421             :  *
     422             :  * This C analog to this is GDALGetDriver().
     423             :  *
     424             :  * @param iDriver the driver index from 0 to GetDriverCount()-1.
     425             :  *
     426             :  * @return the driver identified by the index or NULL if the index is invalid
     427             :  */
     428             : 
     429    12526400 : GDALDriver *GDALDriverManager::GetDriver(int iDriver)
     430             : 
     431             : {
     432    25052900 :     CPLMutexHolderD(&hDMMutex);
     433             : 
     434    25052900 :     return GetDriver_unlocked(iDriver);
     435             : }
     436             : 
     437             : //! @cond Doxygen_Suppress
     438     9203480 : GDALDriver *GDALDriverManager::GetDriver(int iDriver, bool bIncludeHidden)
     439             : 
     440             : {
     441    18407000 :     CPLMutexHolderD(&hDMMutex);
     442     9203480 :     if (!bIncludeHidden || iDriver < nDrivers)
     443     9203480 :         return GetDriver_unlocked(iDriver);
     444           0 :     if (iDriver - nDrivers < static_cast<int>(m_aoHiddenDrivers.size()))
     445           0 :         return m_aoHiddenDrivers[iDriver - nDrivers].get();
     446           0 :     return nullptr;
     447             : }
     448             : 
     449             : //! @endcond
     450             : 
     451             : /************************************************************************/
     452             : /*                           GDALGetDriver()                            */
     453             : /************************************************************************/
     454             : 
     455             : /**
     456             :  * \brief Fetch driver by index.
     457             :  *
     458             :  * @see GDALDriverManager::GetDriver()
     459             :  */
     460             : 
     461       85056 : GDALDriverH CPL_STDCALL GDALGetDriver(int iDriver)
     462             : 
     463             : {
     464       85056 :     return /* (GDALDriverH) */ GetGDALDriverManager()->GetDriver(iDriver);
     465             : }
     466             : 
     467             : /************************************************************************/
     468             : /*                           RegisterDriver()                           */
     469             : /************************************************************************/
     470             : 
     471             : /**
     472             :  * \brief Register a driver for use.
     473             :  *
     474             :  * The C analog is GDALRegisterDriver().
     475             :  *
     476             :  * Normally this method is used by format specific C callable registration
     477             :  * entry points such as GDALRegister_GTiff() rather than being called
     478             :  * directly by application level code.
     479             :  *
     480             :  * If this driver (based on the object pointer, not short name) is already
     481             :  * registered, then no change is made, and the index of the existing driver
     482             :  * is returned.  Otherwise the driver list is extended, and the new driver
     483             :  * is added at the end.
     484             :  *
     485             :  * @param poDriver the driver to register.
     486             :  *
     487             :  * @return the index of the new installed driver, or -1 in case of error
     488             :  */
     489             : 
     490      410370 : int GDALDriverManager::RegisterDriver(GDALDriver *poDriver)
     491             : {
     492      410370 :     return RegisterDriver(poDriver, /*bHidden=*/false);
     493             : }
     494             : 
     495      410370 : int GDALDriverManager::RegisterDriver(GDALDriver *poDriver, bool bHidden)
     496             : {
     497      820740 :     CPLMutexHolderD(&hDMMutex);
     498             : 
     499      410370 :     const char *pszDriverName = poDriver->GetDescription();
     500      410370 :     if (pszDriverName[0] == 0)
     501             :     {
     502           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     503             :                  "Cannot register driver with empty name");
     504           0 :         return -1;
     505             :     }
     506      410370 :     if (pszDriverName[0] == '-')
     507             :     {
     508             :         // Because GDALDataset::Open() considers that strings in the allowed
     509             :         // drivers list starting with dash mean to exclude a driver.
     510           0 :         CPLError(
     511             :             CE_Failure, CPLE_AppDefined,
     512             :             "Cannot register driver whose name starts with a dash character");
     513           0 :         return -1;
     514             :     }
     515             : 
     516             :     /* -------------------------------------------------------------------- */
     517             :     /*      If it is already registered, just return the existing           */
     518             :     /*      index.                                                          */
     519             :     /* -------------------------------------------------------------------- */
     520      819987 :     if (!m_bInDeferredDriverLoading &&
     521      409617 :         GetDriverByName_unlocked(pszDriverName) != nullptr)
     522             :     {
     523         227 :         for (int i = 0; i < nDrivers; ++i)
     524             :         {
     525         227 :             if (papoDrivers[i] == poDriver)
     526             :             {
     527           1 :                 return i;
     528             :             }
     529             :         }
     530             : 
     531           0 :         CPLAssert(false);
     532             :     }
     533             : 
     534      410369 :     if (poDriver->pfnOpen != nullptr ||
     535       82946 :         poDriver->pfnOpenWithDriverArg != nullptr)
     536      327426 :         poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     537             : 
     538      410369 :     if (poDriver->pfnCreate != nullptr || poDriver->pfnCreateEx != nullptr)
     539      124822 :         poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     540             : 
     541      410369 :     if (poDriver->pfnCreateCopy != nullptr)
     542       67105 :         poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     543             : 
     544      410369 :     if (poDriver->pfnCreateMultiDimensional != nullptr)
     545        5457 :         poDriver->SetMetadataItem(GDAL_DCAP_CREATE_MULTIDIMENSIONAL, "YES");
     546             : 
     547             :     // Backward compatibility for GDAL raster out-of-tree drivers:
     548             :     // If a driver hasn't explicitly set a vector capability, assume it is
     549             :     // a raster-only driver (legacy OGR drivers will have DCAP_VECTOR set before
     550             :     // calling RegisterDriver()).
     551      410369 :     if (poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr &&
     552      130094 :         poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
     553      544072 :         poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr &&
     554        3609 :         poDriver->GetMetadataItem(GDAL_DCAP_GNM) == nullptr)
     555             :     {
     556           3 :         CPLDebug("GDAL", "Assuming DCAP_RASTER for driver %s. Please fix it.",
     557             :                  pszDriverName);
     558           3 :         poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     559             :     }
     560             : 
     561      410369 :     if (poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST) != nullptr &&
     562      159149 :         poDriver->pfnIdentify == nullptr &&
     563      573124 :         poDriver->pfnIdentifyEx == nullptr &&
     564        3606 :         !STARTS_WITH_CI(pszDriverName, "Interlis"))
     565             :     {
     566           0 :         CPLDebug("GDAL",
     567             :                  "Driver %s that defines GDAL_DMD_OPENOPTIONLIST must also "
     568             :                  "implement Identify(), so that it can be used",
     569             :                  pszDriverName);
     570             :     }
     571             : 
     572      410369 :     if (poDriver->pfnVectorTranslateFrom != nullptr)
     573        3606 :         poDriver->SetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM, "YES");
     574             : 
     575      411122 :     if (m_bInDeferredDriverLoading &&
     576      411122 :         cpl::contains(oMapNameToDrivers, CPLString(pszDriverName).toupper()))
     577             :     {
     578         752 :         if (cpl::contains(m_oMapRealDrivers, pszDriverName))
     579             :         {
     580           0 :             CPLError(
     581             :                 CE_Failure, CPLE_AppDefined,
     582             :                 "RegisterDriver() in m_bInDeferredDriverLoading: %s already "
     583             :                 "registered!",
     584             :                 pszDriverName);
     585           0 :             delete poDriver;
     586           0 :             return -1;
     587             :         }
     588        1504 :         m_oMapRealDrivers[pszDriverName] =
     589        2256 :             std::unique_ptr<GDALDriver>(poDriver);
     590         752 :         return -1;
     591             :     }
     592             : 
     593             :     /* -------------------------------------------------------------------- */
     594             :     /*      Otherwise grow the list to hold the new entry.                  */
     595             :     /* -------------------------------------------------------------------- */
     596      409617 :     if (bHidden)
     597             :     {
     598           0 :         m_aoHiddenDrivers.push_back(std::unique_ptr<GDALDriver>(poDriver));
     599           0 :         return -1;
     600             :     }
     601             : 
     602             :     GDALDriver **papoNewDrivers =
     603      409617 :         static_cast<GDALDriver **>(VSI_REALLOC_VERBOSE(
     604             :             papoDrivers, sizeof(GDALDriver *) * (nDrivers + 1)));
     605      409617 :     if (papoNewDrivers == nullptr)
     606           0 :         return -1;
     607      409617 :     papoDrivers = papoNewDrivers;
     608             : 
     609      409617 :     papoDrivers[nDrivers] = poDriver;
     610      409617 :     ++nDrivers;
     611             : 
     612      409617 :     oMapNameToDrivers[CPLString(pszDriverName).toupper()] = poDriver;
     613             : 
     614      411421 :     if (EQUAL(pszDriverName, "MEM") &&
     615      411421 :         oMapNameToDrivers.find("MEMORY") == oMapNameToDrivers.end())
     616             :     {
     617             :         // Instantiate a Memory driver, that is the same as the MEM one,
     618             :         // for legacy purposes. It can be queried through GetDriverByName()
     619             :         // but doesn't appear in the driver list.
     620        1803 :         auto poMemoryDriver = new GDALDriver();
     621        1803 :         poMemoryDriver->SetDescription("Memory");
     622        1803 :         poMemoryDriver->SetMetadata(poDriver->GetMetadata());
     623        1803 :         poMemoryDriver->pfnOpen = poDriver->pfnOpen;
     624        1803 :         poMemoryDriver->pfnIdentify = poDriver->pfnIdentify;
     625        1803 :         poMemoryDriver->pfnCreate = poDriver->pfnCreate;
     626        1803 :         poMemoryDriver->pfnCreateMultiDimensional =
     627        1803 :             poDriver->pfnCreateMultiDimensional;
     628        1803 :         poMemoryDriver->pfnDelete = poDriver->pfnDelete;
     629        3606 :         oMapNameToDrivers[CPLString(poMemoryDriver->GetDescription())
     630        3606 :                               .toupper()] = poMemoryDriver;
     631             :     }
     632             : 
     633      409617 :     int iResult = nDrivers - 1;
     634             : 
     635      409617 :     return iResult;
     636             : }
     637             : 
     638             : /************************************************************************/
     639             : /*                      GetDriverByName_unlocked()                      */
     640             : /************************************************************************/
     641             : 
     642             : GDALDriver *
     643     1012690 : GDALDriverManager::GetDriverByName_unlocked(const char *pszName) const
     644             : {
     645     1012690 :     const CPLString osName = CPLString(pszName).toupper();
     646     1012690 :     if (osName == "MEMORY")
     647             :     {
     648          47 :         CPLErrorOnce(CE_Warning, CPLE_AppDefined,
     649             :                      "DeprecationWarning: 'Memory' driver is deprecated since "
     650             :                      "GDAL 3.11. Use 'MEM' onwards");
     651             :     }
     652     1012690 :     auto oIter = oMapNameToDrivers.find(osName);
     653     2025390 :     return oIter == oMapNameToDrivers.end() ? nullptr : oIter->second;
     654             : }
     655             : 
     656             : /************************************************************************/
     657             : /*                         GDALRegisterDriver()                         */
     658             : /************************************************************************/
     659             : 
     660             : /**
     661             :  * \brief Register a driver for use.
     662             :  *
     663             :  * @see GDALDriverManager::GetRegisterDriver()
     664             :  */
     665             : 
     666          95 : int CPL_STDCALL GDALRegisterDriver(GDALDriverH hDriver)
     667             : 
     668             : {
     669          95 :     VALIDATE_POINTER1(hDriver, "GDALRegisterDriver", 0);
     670             : 
     671          95 :     return GetGDALDriverManager()->RegisterDriver(
     672          95 :         static_cast<GDALDriver *>(hDriver));
     673             : }
     674             : 
     675             : /************************************************************************/
     676             : /*                          DeregisterDriver()                          */
     677             : /************************************************************************/
     678             : 
     679             : /**
     680             :  * \brief Deregister the passed driver.
     681             :  *
     682             :  * If the driver isn't found no change is made.
     683             :  *
     684             :  * The C analog is GDALDeregisterDriver().
     685             :  *
     686             :  * @param poDriver the driver to deregister.
     687             :  */
     688             : 
     689      257977 : void GDALDriverManager::DeregisterDriver(GDALDriver *poDriver)
     690             : 
     691             : {
     692      257977 :     CPLMutexHolderD(&hDMMutex);
     693             : 
     694      257977 :     int i = 0;  // Used after for.
     695      278753 :     for (; i < nDrivers; ++i)
     696             :     {
     697      278752 :         if (papoDrivers[i] == poDriver)
     698      257976 :             break;
     699             :     }
     700             : 
     701      257977 :     if (i == nDrivers)
     702           1 :         return;
     703             : 
     704      257976 :     oMapNameToDrivers.erase(CPLString(poDriver->GetDescription()).toupper());
     705      257976 :     --nDrivers;
     706             :     // Move all following drivers down by one to pack the list.
     707    29400500 :     while (i < nDrivers)
     708             :     {
     709    29142500 :         papoDrivers[i] = papoDrivers[i + 1];
     710    29142500 :         ++i;
     711             :     }
     712             : }
     713             : 
     714             : /************************************************************************/
     715             : /*                        GDALDeregisterDriver()                        */
     716             : /************************************************************************/
     717             : 
     718             : /**
     719             :  * \brief Deregister the passed driver.
     720             :  *
     721             :  * @see GDALDriverManager::GetDeregisterDriver()
     722             :  */
     723             : 
     724          95 : void CPL_STDCALL GDALDeregisterDriver(GDALDriverH hDriver)
     725             : 
     726             : {
     727          95 :     VALIDATE_POINTER0(hDriver, "GDALDeregisterDriver");
     728             : 
     729          95 :     GetGDALDriverManager()->DeregisterDriver(
     730             :         static_cast<GDALDriver *>(hDriver));
     731             : }
     732             : 
     733             : /************************************************************************/
     734             : /*                          GetDriverByName()                           */
     735             : /************************************************************************/
     736             : 
     737             : /**
     738             :  * \brief Fetch a driver based on the short name.
     739             :  *
     740             :  * The C analog is the GDALGetDriverByName() function.
     741             :  *
     742             :  * @param pszName the short name, such as GTiff, being searched for.
     743             :  *
     744             :  * @return the identified driver, or NULL if no match is found.
     745             :  */
     746             : 
     747      603830 : GDALDriver *GDALDriverManager::GetDriverByName(const char *pszName)
     748             : 
     749             : {
     750     1207660 :     CPLMutexHolderD(&hDMMutex);
     751             : 
     752      603830 :     if (m_bInDeferredDriverLoading)
     753             :     {
     754         753 :         return nullptr;
     755             :     }
     756             : 
     757             :     // Alias old name to new name
     758      603077 :     if (EQUAL(pszName, "CartoDB"))
     759           0 :         pszName = "Carto";
     760             : 
     761      603077 :     return GetDriverByName_unlocked(pszName);
     762             : }
     763             : 
     764             : /************************************************************************/
     765             : /*                        GDALGetDriverByName()                         */
     766             : /************************************************************************/
     767             : 
     768             : /**
     769             :  * \brief Fetch a driver based on the short name.
     770             :  *
     771             :  * @see GDALDriverManager::GetDriverByName()
     772             :  */
     773             : 
     774      575653 : GDALDriverH CPL_STDCALL GDALGetDriverByName(const char *pszName)
     775             : 
     776             : {
     777      575653 :     VALIDATE_POINTER1(pszName, "GDALGetDriverByName", nullptr);
     778             : 
     779      575653 :     return GetGDALDriverManager()->GetDriverByName(pszName);
     780             : }
     781             : 
     782             : /************************************************************************/
     783             : /*                          AutoSkipDrivers()                           */
     784             : /************************************************************************/
     785             : 
     786             : /**
     787             :  * \brief This method unload undesirable drivers.
     788             :  *
     789             :  * All drivers specified in the comma delimited list in the GDAL_SKIP
     790             :  * environment variable) will be deregistered and destroyed.  This method
     791             :  * should normally be called after registration of standard drivers to allow
     792             :  * the user a way of unloading undesired drivers.  The GDALAllRegister()
     793             :  * function already invokes AutoSkipDrivers() at the end, so if that functions
     794             :  * is called, it should not be necessary to call this method from application
     795             :  * code.
     796             :  *
     797             :  * Note: space separator is also accepted for backward compatibility, but some
     798             :  * vector formats have spaces in their names, so it is encouraged to use comma
     799             :  * to avoid issues.
     800             :  */
     801             : 
     802        2067 : void GDALDriverManager::AutoSkipDrivers()
     803             : 
     804             : {
     805        2067 :     char **apapszList[2] = {nullptr, nullptr};
     806        2067 :     const char *pszGDAL_SKIP = CPLGetConfigOption("GDAL_SKIP", nullptr);
     807        2067 :     if (pszGDAL_SKIP != nullptr)
     808             :     {
     809             :         // Favor comma as a separator. If not found, then use space.
     810           5 :         const char *pszSep = (strchr(pszGDAL_SKIP, ',') != nullptr) ? "," : " ";
     811           5 :         apapszList[0] =
     812           5 :             CSLTokenizeStringComplex(pszGDAL_SKIP, pszSep, FALSE, FALSE);
     813             :     }
     814        2067 :     const char *pszOGR_SKIP = CPLGetConfigOption("OGR_SKIP", nullptr);
     815        2067 :     if (pszOGR_SKIP != nullptr)
     816             :     {
     817             :         // OGR has always used comma as a separator.
     818           4 :         apapszList[1] =
     819           4 :             CSLTokenizeStringComplex(pszOGR_SKIP, ",", FALSE, FALSE);
     820             :     }
     821             : 
     822        6201 :     for (auto j : {0, 1})
     823             :     {
     824        4143 :         for (int i = 0; apapszList[j] != nullptr && apapszList[j][i] != nullptr;
     825             :              ++i)
     826             :         {
     827           9 :             GDALDriver *const poDriver = GetDriverByName(apapszList[j][i]);
     828             : 
     829           9 :             if (poDriver == nullptr)
     830             :             {
     831           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     832             :                          "Unable to find driver %s to unload from GDAL_SKIP "
     833             :                          "environment variable.",
     834           0 :                          apapszList[j][i]);
     835             :             }
     836             :             else
     837             :             {
     838           9 :                 CPLDebug("GDAL", "AutoSkipDriver(%s)", apapszList[j][i]);
     839           9 :                 DeregisterDriver(poDriver);
     840           9 :                 delete poDriver;
     841             :             }
     842             :         }
     843             :     }
     844             : 
     845        2067 :     CSLDestroy(apapszList[0]);
     846        2067 :     CSLDestroy(apapszList[1]);
     847        2067 : }
     848             : 
     849             : /************************************************************************/
     850             : /*                           GetSearchPaths()                           */
     851             : /************************************************************************/
     852             : 
     853             : //! @cond Doxygen_Suppress
     854        5938 : char **GDALDriverManager::GetSearchPaths(const char *pszGDAL_DRIVER_PATH)
     855             : {
     856        5938 :     char **papszSearchPaths = nullptr;
     857        5938 :     CPL_IGNORE_RET_VAL(pszGDAL_DRIVER_PATH);
     858             : #ifndef GDAL_NO_AUTOLOAD
     859        5938 :     if (pszGDAL_DRIVER_PATH != nullptr)
     860             :     {
     861             : #ifdef _WIN32
     862             :         papszSearchPaths =
     863             :             CSLTokenizeStringComplex(pszGDAL_DRIVER_PATH, ";", TRUE, FALSE);
     864             : #else
     865             :         papszSearchPaths =
     866        5938 :             CSLTokenizeStringComplex(pszGDAL_DRIVER_PATH, ":", TRUE, FALSE);
     867             : #endif
     868             :     }
     869             :     else
     870             :     {
     871             : #ifdef INSTALL_PLUGIN_FULL_DIR
     872             :         // CMake way
     873             :         papszSearchPaths =
     874           0 :             CSLAddString(papszSearchPaths, INSTALL_PLUGIN_FULL_DIR);
     875             : #elif defined(GDAL_PREFIX)
     876             :         papszSearchPaths = CSLAddString(papszSearchPaths,
     877             : #ifdef MACOSX_FRAMEWORK
     878             :                                         GDAL_PREFIX "/PlugIns");
     879             : #else
     880             :                                         GDAL_PREFIX "/lib/gdalplugins");
     881             : #endif
     882             : #else
     883             :         char szExecPath[1024];
     884             : 
     885             :         if (CPLGetExecPath(szExecPath, sizeof(szExecPath)))
     886             :         {
     887             :             papszSearchPaths = CSLAddString(
     888             :                 papszSearchPaths,
     889             :                 (CPLGetDirnameSafe(szExecPath) + "\\gdalplugins").c_str());
     890             :         }
     891             :         else
     892             :         {
     893             :             papszSearchPaths =
     894             :                 CSLAddString(papszSearchPaths, "/usr/local/lib/gdalplugins");
     895             :         }
     896             : #endif
     897             : 
     898             : #ifdef MACOSX_FRAMEWORK
     899             : #define num2str(x) str(x)
     900             : #define str(x) #x
     901             :         papszSearchPaths = CSLAddString(
     902             :             papszSearchPaths,
     903             :             "/Library/Application Support/GDAL/" num2str(
     904             :                 GDAL_VERSION_MAJOR) "." num2str(GDAL_VERSION_MINOR) "/PlugIns");
     905             : #endif
     906             :     }
     907             : #endif  // GDAL_NO_AUTOLOAD
     908        5938 :     return papszSearchPaths;
     909             : }
     910             : 
     911             : //! @endcond
     912             : 
     913             : /************************************************************************/
     914             : /*                             LoadPlugin()                             */
     915             : /************************************************************************/
     916             : 
     917             : /**
     918             :  * \brief Load a single GDAL driver/plugin from shared libraries.
     919             :  *
     920             :  * This function will load a single named driver/plugin from shared libraries.
     921             :  * It searches the "driver path" for .so (or .dll) files named
     922             :  * "gdal_{name}.[so|dll|dylib]" or "ogr_{name}.[so|dll|dylib]", then tries to
     923             :  * call a function within them called GDALRegister_{name}(), or failing that
     924             :  * called GDALRegisterMe().
     925             :  *
     926             :  * \see GDALDriverManager::AutoLoadDrivers() for the rules used to determine
     927             :  * which paths are searched for plugin library files.
     928             :  */
     929             : 
     930           1 : CPLErr GDALDriverManager::LoadPlugin(const char *name)
     931             : {
     932             : #ifdef GDAL_NO_AUTOLOAD
     933             :     CPLDebug("GDAL", "GDALDriverManager::LoadPlugin() not compiled in.");
     934             :     return CE_Failure;
     935             : #else
     936             :     const char *pszGDAL_DRIVER_PATH =
     937           1 :         CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr);
     938           1 :     if (pszGDAL_DRIVER_PATH == nullptr)
     939           0 :         pszGDAL_DRIVER_PATH = CPLGetConfigOption("OGR_DRIVER_PATH", nullptr);
     940             : 
     941             :     /* -------------------------------------------------------------------- */
     942             :     /*      Where should we look for stuff?                                 */
     943             :     /* -------------------------------------------------------------------- */
     944           2 :     const CPLStringList aosSearchPaths(GetSearchPaths(pszGDAL_DRIVER_PATH));
     945             : 
     946             :     /* -------------------------------------------------------------------- */
     947             :     /*      Format the ABI version specific subdirectory to look in.        */
     948             :     /* -------------------------------------------------------------------- */
     949           2 :     CPLString osABIVersion;
     950             : 
     951           1 :     osABIVersion.Printf("%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
     952             : 
     953             :     /* -------------------------------------------------------------------- */
     954             :     /*      Scan each directory looking for files matching                  */
     955             :     /*      gdal_{name}.[so|dll|dylib] or ogr_{name}.[so|dll|dylib]         */
     956             :     /* -------------------------------------------------------------------- */
     957           1 :     const int nSearchPaths = aosSearchPaths.size();
     958           2 :     for (int iDir = 0; iDir < nSearchPaths; ++iDir)
     959             :     {
     960             :         std::string osABISpecificDir =
     961           1 :             CPLFormFilenameSafe(aosSearchPaths[iDir], osABIVersion, nullptr);
     962             : 
     963             :         VSIStatBufL sStatBuf;
     964           1 :         if (VSIStatL(osABISpecificDir.c_str(), &sStatBuf) != 0)
     965           1 :             osABISpecificDir = aosSearchPaths[iDir];
     966             : 
     967           3 :         CPLString gdal_or_ogr[2] = {"gdal_", "ogr_"};
     968           4 :         CPLString platformExtensions[3] = {"so", "dll", "dylib"};
     969             : 
     970           3 :         for (const CPLString &prefix : gdal_or_ogr)
     971             :         {
     972           8 :             for (const CPLString &extension : platformExtensions)
     973             :             {
     974             :                 const std::string osFilename = CPLFormFilenameSafe(
     975             :                     osABISpecificDir.c_str(),
     976           6 :                     CPLSPrintf("%s%s", prefix.c_str(), name), extension);
     977           6 :                 if (VSIStatL(osFilename.c_str(), &sStatBuf) != 0)
     978           6 :                     continue;
     979             : 
     980           0 :                 CPLString osFuncName;
     981           0 :                 if (EQUAL(prefix, "gdal_"))
     982             :                 {
     983           0 :                     osFuncName.Printf("GDALRegister_%s", name);
     984             :                 }
     985             :                 else
     986             :                 {
     987           0 :                     osFuncName.Printf("RegisterOGR%s", name);
     988             :                 }
     989           0 :                 CPLErrorReset();
     990           0 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
     991           0 :                 void *pRegister = CPLGetSymbol(osFilename.c_str(), osFuncName);
     992           0 :                 CPLPopErrorHandler();
     993           0 :                 if (pRegister == nullptr)
     994             :                 {
     995           0 :                     CPLString osLastErrorMsg(CPLGetLastErrorMsg());
     996           0 :                     osFuncName = "GDALRegisterMe";
     997           0 :                     pRegister = CPLGetSymbol(osFilename.c_str(), osFuncName);
     998           0 :                     if (pRegister == nullptr)
     999             :                     {
    1000           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1001             :                                  osLastErrorMsg.c_str());
    1002           0 :                         return CE_Failure;
    1003             :                     }
    1004             :                 }
    1005           0 :                 CPLDebug("GDAL", "Registering %s using %s in %s", name,
    1006             :                          osFuncName.c_str(), osFilename.c_str());
    1007           0 :                 CPLErrorReset();
    1008           0 :                 reinterpret_cast<void (*)()>(pRegister)();
    1009           0 :                 if (CPLGetErrorCounter() > 0)
    1010             :                 {
    1011           0 :                     return CE_Failure;
    1012             :                 }
    1013           0 :                 return CE_None;
    1014             :             }
    1015             :         }
    1016             :     }
    1017           1 :     CPLError(CE_Failure, CPLE_AppDefined,
    1018             :              "Failed to find driver %s in configured driver paths.", name);
    1019           1 :     return CE_Failure;
    1020             : #endif  // GDAL_NO_AUTOLOAD
    1021             : }
    1022             : 
    1023             : /************************************************************************/
    1024             : /*                          AutoLoadDrivers()                           */
    1025             : /************************************************************************/
    1026             : 
    1027             : /**
    1028             :  * \brief Auto-load GDAL drivers from shared libraries.
    1029             :  *
    1030             :  * This function will automatically load drivers from shared libraries.  It
    1031             :  * searches the "driver path" for .so (or .dll) files that start with the
    1032             :  * prefix "gdal_X.so".  It then tries to load them and then tries to call a
    1033             :  * function within them called GDALRegister_X() where the 'X' is the same as
    1034             :  * the remainder of the shared library basename ('X' is case sensitive), or
    1035             :  * failing that to call GDALRegisterMe().
    1036             :  *
    1037             :  * There are a few rules for the driver path.  If the GDAL_DRIVER_PATH
    1038             :  * environment variable it set, it is taken to be a list of directories to
    1039             :  * search separated by colons on UNIX, or semi-colons on Windows.  Otherwise
    1040             :  * the /usr/local/lib/gdalplugins directory, and (if known) the
    1041             :  * lib/gdalplugins subdirectory of the gdal home directory are searched on
    1042             :  * UNIX and \$(BINDIR)\\gdalplugins on Windows.
    1043             :  *
    1044             :  * Auto loading can be completely disabled by setting the GDAL_DRIVER_PATH
    1045             :  * config option to "disable".
    1046             :  *
    1047             :  * Starting with gdal 3.5, the default search path \$(prefix)/lib/gdalplugins
    1048             :  * can be overridden at compile time by passing
    1049             :  * -DINSTALL_PLUGIN_DIR=/another/path to cmake.
    1050             :  */
    1051             : 
    1052        2067 : void GDALDriverManager::AutoLoadDrivers()
    1053             : 
    1054             : {
    1055             : #ifdef GDAL_NO_AUTOLOAD
    1056             :     CPLDebug("GDAL", "GDALDriverManager::AutoLoadDrivers() not compiled in.");
    1057             : #else
    1058             :     const char *pszGDAL_DRIVER_PATH =
    1059        2067 :         CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr);
    1060        2067 :     if (pszGDAL_DRIVER_PATH == nullptr)
    1061           0 :         pszGDAL_DRIVER_PATH = CPLGetConfigOption("OGR_DRIVER_PATH", nullptr);
    1062             : 
    1063             :     /* -------------------------------------------------------------------- */
    1064             :     /*      Allow applications to completely disable this search by         */
    1065             :     /*      setting the driver path to the special string "disable".        */
    1066             :     /* -------------------------------------------------------------------- */
    1067        2067 :     if (pszGDAL_DRIVER_PATH != nullptr && EQUAL(pszGDAL_DRIVER_PATH, "disable"))
    1068             :     {
    1069           0 :         CPLDebug("GDAL", "GDALDriverManager::AutoLoadDrivers() disabled.");
    1070           0 :         return;
    1071             :     }
    1072             : 
    1073             :     /* -------------------------------------------------------------------- */
    1074             :     /*      Where should we look for stuff?                                 */
    1075             :     /* -------------------------------------------------------------------- */
    1076        2067 :     char **papszSearchPaths = GetSearchPaths(pszGDAL_DRIVER_PATH);
    1077             : 
    1078             :     /* -------------------------------------------------------------------- */
    1079             :     /*      Format the ABI version specific subdirectory to look in.        */
    1080             :     /* -------------------------------------------------------------------- */
    1081        4134 :     CPLString osABIVersion;
    1082             : 
    1083        2067 :     osABIVersion.Printf("%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
    1084             : 
    1085             :     /* -------------------------------------------------------------------- */
    1086             :     /*      Scan each directory looking for files starting with gdal_       */
    1087             :     /* -------------------------------------------------------------------- */
    1088        2067 :     const int nSearchPaths = CSLCount(papszSearchPaths);
    1089        2067 :     bool bFoundOnePlugin = false;
    1090        4134 :     for (int iDir = 0; iDir < nSearchPaths; ++iDir)
    1091             :     {
    1092             :         std::string osABISpecificDir =
    1093        4134 :             CPLFormFilenameSafe(papszSearchPaths[iDir], osABIVersion, nullptr);
    1094             : 
    1095             :         VSIStatBufL sStatBuf;
    1096        2067 :         if (VSIStatL(osABISpecificDir.c_str(), &sStatBuf) != 0)
    1097        2067 :             osABISpecificDir = papszSearchPaths[iDir];
    1098             : 
    1099        2067 :         char **papszFiles = VSIReadDir(osABISpecificDir.c_str());
    1100        2067 :         const int nFileCount = CSLCount(papszFiles);
    1101             : 
    1102       82680 :         for (int iFile = 0; iFile < nFileCount; ++iFile)
    1103             :         {
    1104             :             const CPLString osExtension =
    1105       80613 :                 CPLGetExtensionSafe(papszFiles[iFile]);
    1106             : 
    1107       86814 :             if (!EQUAL(osExtension, "dll") && !EQUAL(osExtension, "so") &&
    1108        6201 :                 !EQUAL(osExtension, "dylib"))
    1109             :             {
    1110        6201 :                 if (strcmp(papszFiles[iFile], "drivers.ini") == 0)
    1111             :                 {
    1112        4134 :                     m_osDriversIniPath = CPLFormFilenameSafe(
    1113        4134 :                         osABISpecificDir.c_str(), papszFiles[iFile], nullptr);
    1114             :                 }
    1115        6201 :                 continue;
    1116             :             }
    1117             : 
    1118       74412 :             if (cpl::contains(m_oSetPluginFileNames, papszFiles[iFile]))
    1119             :             {
    1120       72345 :                 continue;
    1121             :             }
    1122             : 
    1123        2067 :             CPLString osFuncName;
    1124        2067 :             if (STARTS_WITH_CI(papszFiles[iFile], "gdal_"))
    1125             :             {
    1126             :                 osFuncName.Printf(
    1127             :                     "GDALRegister_%s",
    1128           0 :                     CPLGetBasenameSafe(papszFiles[iFile]).c_str() +
    1129           0 :                         strlen("gdal_"));
    1130             :             }
    1131        2067 :             else if (STARTS_WITH_CI(papszFiles[iFile], "ogr_"))
    1132             :             {
    1133             :                 osFuncName.Printf(
    1134             :                     "RegisterOGR%s",
    1135           0 :                     CPLGetBasenameSafe(papszFiles[iFile]).c_str() +
    1136           0 :                         strlen("ogr_"));
    1137             :             }
    1138             :             else
    1139        2067 :                 continue;
    1140             : 
    1141             :             const std::string osFilename = CPLFormFilenameSafe(
    1142           0 :                 osABISpecificDir.c_str(), papszFiles[iFile], nullptr);
    1143             : 
    1144           0 :             CPLErrorReset();
    1145           0 :             CPLPushErrorHandler(CPLQuietErrorHandler);
    1146           0 :             void *pRegister = CPLGetSymbol(osFilename.c_str(), osFuncName);
    1147           0 :             CPLPopErrorHandler();
    1148           0 :             if (pRegister == nullptr)
    1149             :             {
    1150           0 :                 CPLString osLastErrorMsg(CPLGetLastErrorMsg());
    1151           0 :                 osFuncName = "GDALRegisterMe";
    1152           0 :                 pRegister = CPLGetSymbol(osFilename.c_str(), osFuncName);
    1153           0 :                 if (pRegister == nullptr)
    1154             :                 {
    1155           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1156             :                              osLastErrorMsg.c_str());
    1157             :                 }
    1158             :             }
    1159             : 
    1160           0 :             if (pRegister != nullptr)
    1161             :             {
    1162           0 :                 bFoundOnePlugin = true;
    1163           0 :                 CPLDebug("GDAL", "Auto register %s using %s.",
    1164             :                          osFilename.c_str(), osFuncName.c_str());
    1165             : 
    1166           0 :                 reinterpret_cast<void (*)()>(pRegister)();
    1167             :             }
    1168             :         }
    1169             : 
    1170        2067 :         CSLDestroy(papszFiles);
    1171             :     }
    1172             : 
    1173        2067 :     CSLDestroy(papszSearchPaths);
    1174             : 
    1175             :     // No need to reorder drivers if there are no plugins
    1176        2067 :     if (!bFoundOnePlugin)
    1177        2067 :         m_osDriversIniPath.clear();
    1178             : 
    1179             : #endif  // GDAL_NO_AUTOLOAD
    1180             : }
    1181             : 
    1182             : /************************************************************************/
    1183             : /*                           ReorderDrivers()                           */
    1184             : /************************************************************************/
    1185             : 
    1186             : /**
    1187             :  * \brief Reorder drivers according to the order of the drivers.ini file.
    1188             :  *
    1189             :  * This function is called by GDALAllRegister(), at the end of driver loading,
    1190             :  * in particular after plugin loading.
    1191             :  * It will load the drivers.ini configuration file located next to plugins and
    1192             :  * will use it to reorder the registration order of drivers. This can be
    1193             :  * important in some situations where multiple drivers could open the same
    1194             :  * dataset.
    1195             :  */
    1196             : 
    1197        2067 : void GDALDriverManager::ReorderDrivers()
    1198             : {
    1199             : #ifndef GDAL_NO_AUTOLOAD
    1200        2067 :     if (m_osDriversIniPath.empty())
    1201             :     {
    1202        2067 :         if (m_oSetPluginFileNames.empty())
    1203           0 :             return;
    1204             : 
    1205        2067 :         m_osDriversIniPath = GetPluginFullPath("drivers.ini");
    1206        2067 :         if (m_osDriversIniPath.empty())
    1207           0 :             return;
    1208             :     }
    1209             : 
    1210        2067 :     CPLMutexHolderD(&hDMMutex);
    1211             : 
    1212        2067 :     VSILFILE *fp = VSIFOpenL(m_osDriversIniPath.c_str(), "rb");
    1213        2067 :     if (fp == nullptr)
    1214           0 :         return;
    1215             : 
    1216             :     // Parse drivers.ini
    1217        2067 :     bool bInOrderSection = false;
    1218        4134 :     std::vector<std::string> aosOrderedDrivers;
    1219        4134 :     std::set<std::string> oSetOrderedDrivers;
    1220      591162 :     while (const char *pszLine = CPLReadLine2L(fp, 1024, nullptr))
    1221             :     {
    1222      589095 :         if (pszLine[0] == '#')
    1223       68211 :             continue;
    1224      539487 :         int i = 0;
    1225      539487 :         while (pszLine[i] != 0 &&
    1226      520884 :                isspace(static_cast<unsigned char>(pszLine[i])))
    1227           0 :             i++;
    1228      539487 :         if (pszLine[i] == 0)
    1229       18603 :             continue;
    1230      520884 :         if (strcmp(pszLine, "[order]") == 0)
    1231             :         {
    1232        2067 :             bInOrderSection = true;
    1233             :         }
    1234      518817 :         else if (pszLine[0] == '[')
    1235             :         {
    1236           0 :             bInOrderSection = false;
    1237             :         }
    1238      518817 :         else if (bInOrderSection)
    1239             :         {
    1240     1037630 :             CPLString osUCDriverName(pszLine);
    1241      518817 :             osUCDriverName.toupper();
    1242      518817 :             if (osUCDriverName != "MEMORY")
    1243             :             {
    1244      518817 :                 if (cpl::contains(oSetOrderedDrivers, osUCDriverName))
    1245             :                 {
    1246           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1247             :                              "Duplicated name %s in [order] section", pszLine);
    1248             :                 }
    1249      518817 :                 else if (cpl::contains(oMapNameToDrivers, osUCDriverName))
    1250             :                 {
    1251      469460 :                     aosOrderedDrivers.emplace_back(pszLine);
    1252      469460 :                     oSetOrderedDrivers.insert(std::move(osUCDriverName));
    1253             :                 }
    1254             : #ifdef DEBUG_VERBOSE
    1255             :                 else
    1256             :                 {
    1257             :                     // Completely expected situation for "non-maximal" builds,
    1258             :                     // but can help diagnose bad entries in drivers.ini
    1259             :                     CPLDebug("GDAL",
    1260             :                              "Driver %s is listed in %s but not registered.",
    1261             :                              pszLine, m_osDriversIniPath.c_str());
    1262             :                 }
    1263             : #endif
    1264             :             }
    1265             :         }
    1266      589095 :     }
    1267        2067 :     VSIFCloseL(fp);
    1268             : 
    1269             :     // Find potential registered drivers not in drivers.ini, and put them in
    1270             :     // their registration order in aosUnorderedDrivers
    1271        4134 :     std::vector<std::string> aosUnorderedDrivers;
    1272      471536 :     for (int i = 0; i < nDrivers; ++i)
    1273             :     {
    1274      469469 :         const char *pszName = papoDrivers[i]->GetDescription();
    1275      469469 :         if (!cpl::contains(oSetOrderedDrivers, CPLString(pszName).toupper()))
    1276             :         {
    1277             :             // Could happen for a private plugin
    1278           9 :             CPLDebug("GDAL",
    1279             :                      "Driver %s is registered but not listed in %s. "
    1280             :                      "It will be registered before other drivers.",
    1281             :                      pszName, m_osDriversIniPath.c_str());
    1282           9 :             aosUnorderedDrivers.emplace_back(pszName);
    1283             :         }
    1284             :     }
    1285             : 
    1286             :     // Put aosUnorderedDrivers in front of existing aosOrderedDrivers
    1287        2067 :     if (!aosUnorderedDrivers.empty())
    1288             :     {
    1289           7 :         aosUnorderedDrivers.insert(aosUnorderedDrivers.end(),
    1290             :                                    aosOrderedDrivers.begin(),
    1291          14 :                                    aosOrderedDrivers.end());
    1292           7 :         std::swap(aosOrderedDrivers, aosUnorderedDrivers);
    1293             :     }
    1294             : 
    1295             :     // Update papoDrivers[] to reflect aosOrderedDrivers order.
    1296        2067 :     CPLAssert(static_cast<int>(aosOrderedDrivers.size()) == nDrivers);
    1297      471536 :     for (int i = 0; i < nDrivers; ++i)
    1298             :     {
    1299             :         const auto oIter =
    1300      469469 :             oMapNameToDrivers.find(CPLString(aosOrderedDrivers[i]).toupper());
    1301      469469 :         CPLAssert(oIter != oMapNameToDrivers.end());
    1302      469469 :         papoDrivers[i] = oIter->second;
    1303             :     }
    1304             : #endif
    1305             : }
    1306             : 
    1307             : /************************************************************************/
    1308             : /*                        GDALPluginDriverProxy                         */
    1309             : /************************************************************************/
    1310             : 
    1311             : /** Constructor for a plugin driver proxy.
    1312             :  *
    1313             :  * @param osPluginFileName Plugin filename. e.g "ogr_Parquet.so"
    1314             :  */
    1315       79332 : GDALPluginDriverProxy::GDALPluginDriverProxy(
    1316       79332 :     const std::string &osPluginFileName)
    1317       79332 :     : m_osPluginFileName(osPluginFileName)
    1318             : {
    1319       79332 : }
    1320             : 
    1321             : //! @cond Doxygen_Suppress
    1322             : #define DEFINE_DRIVER_METHOD_GET_CALLBACK(method_name, output_type)            \
    1323             :     GDALDriver::output_type GDALPluginDriverProxy::method_name()               \
    1324             :     {                                                                          \
    1325             :         auto poRealDriver = GetRealDriver();                                   \
    1326             :         if (!poRealDriver)                                                     \
    1327             :             return nullptr;                                                    \
    1328             :         return poRealDriver->method_name();                                    \
    1329             :     }
    1330             : 
    1331       13276 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetOpenCallback, OpenCallback)
    1332        1564 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetCreateCallback, CreateCallback)
    1333         135 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetCreateMultiDimensionalCallback,
    1334             :                                   CreateMultiDimensionalCallback)
    1335        5837 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetCreateCopyCallback, CreateCopyCallback)
    1336         618 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetDeleteCallback, DeleteCallback)
    1337           3 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetRenameCallback, RenameCallback)
    1338           0 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetCopyFilesCallback, CopyFilesCallback)
    1339         287 : DEFINE_DRIVER_METHOD_GET_CALLBACK(GetInstantiateAlgorithmCallback,
    1340             :                                   InstantiateAlgorithmCallback)
    1341             : 
    1342             : //! @endcond
    1343             : 
    1344        2021 : CSLConstList GDALPluginDriverProxy::GetMetadata(const char *pszDomain)
    1345             : {
    1346        2021 :     auto poRealDriver = GetRealDriver();
    1347        2021 :     if (!poRealDriver)
    1348           0 :         return nullptr;
    1349        2021 :     return poRealDriver->GetMetadata(pszDomain);
    1350             : }
    1351             : 
    1352     1083700 : CPLErr GDALPluginDriverProxy::SetMetadataItem(const char *pszName,
    1353             :                                               const char *pszValue,
    1354             :                                               const char *pszDomain)
    1355             : {
    1356     1083700 :     if (!pszDomain || pszDomain[0] == 0)
    1357             :     {
    1358     1083700 :         if (!EQUAL(pszName, GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
    1359             :         {
    1360     1083700 :             m_oSetMetadataItems.insert(pszName);
    1361             :         }
    1362             :     }
    1363     1083700 :     return GDALDriver::SetMetadataItem(pszName, pszValue, pszDomain);
    1364             : }
    1365             : 
    1366             : static const char *const apszProxyMetadataItems[] = {
    1367             :     GDAL_DMD_LONGNAME,
    1368             :     GDAL_DMD_EXTENSIONS,
    1369             :     GDAL_DMD_EXTENSION,
    1370             :     GDAL_DCAP_RASTER,
    1371             :     GDAL_DCAP_MULTIDIM_RASTER,
    1372             :     GDAL_DCAP_VECTOR,
    1373             :     GDAL_DCAP_GNM,
    1374             :     GDAL_DMD_OPENOPTIONLIST,
    1375             :     GDAL_DCAP_OPEN,
    1376             :     GDAL_DCAP_CREATE,
    1377             :     GDAL_DCAP_CREATE_MULTIDIMENSIONAL,
    1378             :     GDAL_DCAP_CREATECOPY,
    1379             :     GDAL_DCAP_UPDATE,
    1380             :     GDAL_DMD_SUBDATASETS,
    1381             :     GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
    1382             :     GDAL_DCAP_NONSPATIAL,
    1383             :     GDAL_DMD_CONNECTION_PREFIX,
    1384             :     GDAL_DCAP_VECTOR_TRANSLATE_FROM,
    1385             :     GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
    1386             : };
    1387             : 
    1388     2513240 : const char *GDALPluginDriverProxy::GetMetadataItem(const char *pszName,
    1389             :                                                    const char *pszDomain)
    1390             : {
    1391     2512620 :     const auto IsListedProxyMetadataItem = [](const char *pszItem)
    1392             :     {
    1393    19623700 :         for (const char *pszListedItem : apszProxyMetadataItems)
    1394             :         {
    1395    19596700 :             if (EQUAL(pszItem, pszListedItem))
    1396     2485600 :                 return true;
    1397             :         }
    1398       27015 :         return false;
    1399             :     };
    1400             : 
    1401     2513240 :     if (!pszDomain || pszDomain[0] == 0)
    1402             :     {
    1403     2513200 :         if (EQUAL(pszName, "IS_NON_LOADED_PLUGIN"))
    1404             :         {
    1405         413 :             return !m_poRealDriver ? "YES" : nullptr;
    1406             :         }
    1407     2512790 :         else if (EQUAL(pszName, "MISSING_PLUGIN_FILENAME"))
    1408             :         {
    1409         171 :             return m_osPluginFullPath.empty() ? m_osPluginFileName.c_str()
    1410         171 :                                               : nullptr;
    1411             :         }
    1412     2512620 :         else if (IsListedProxyMetadataItem(pszName))
    1413             :         {
    1414             :             const char *pszValue =
    1415     2485600 :                 GDALDriver::GetMetadataItem(pszName, pszDomain);
    1416     2485600 :             if (!pszValue && EQUAL(pszName, GDAL_DMD_EXTENSION))
    1417             :             {
    1418             :                 const char *pszOtherValue =
    1419          51 :                     GDALDriver::GetMetadataItem(GDAL_DMD_EXTENSIONS, pszDomain);
    1420          51 :                 if (pszOtherValue && strchr(pszOtherValue, ' '))
    1421          51 :                     return pszOtherValue;
    1422             :             }
    1423     2485550 :             else if (!pszValue && EQUAL(pszName, GDAL_DMD_EXTENSIONS))
    1424             :             {
    1425       11735 :                 return GDALDriver::GetMetadataItem(GDAL_DMD_EXTENSION,
    1426       11735 :                                                    pszDomain);
    1427             :             }
    1428     2473830 :             return pszValue;
    1429             :         }
    1430       27015 :         else if (cpl::contains(m_oSetMetadataItems, pszName))
    1431             :         {
    1432       23837 :             return GDALDriver::GetMetadataItem(pszName, pszDomain);
    1433             :         }
    1434             :     }
    1435             : 
    1436        3218 :     auto poRealDriver = GetRealDriver();
    1437        3218 :     if (!poRealDriver)
    1438           0 :         return nullptr;
    1439        3218 :     return poRealDriver->GetMetadataItem(pszName, pszDomain);
    1440             : }
    1441             : 
    1442             : /************************************************************************/
    1443             : /*                           GetRealDriver()                            */
    1444             : /************************************************************************/
    1445             : 
    1446       26959 : GDALDriver *GDALPluginDriverProxy::GetRealDriver()
    1447             : {
    1448             :     // No need to take the mutex has this member variable is not modified
    1449             :     // under the mutex.
    1450       26959 :     if (m_osPluginFullPath.empty())
    1451           0 :         return nullptr;
    1452             : 
    1453       53918 :     CPLMutexHolderD(&hDMMutex);
    1454             : 
    1455       26959 :     if (m_poRealDriver)
    1456       26250 :         return m_poRealDriver.get();
    1457             : 
    1458         709 :     auto poDriverManager = GetGDALDriverManager();
    1459         709 :     auto oIter = poDriverManager->m_oMapRealDrivers.find(GetDescription());
    1460         709 :     if (oIter != poDriverManager->m_oMapRealDrivers.end())
    1461             :     {
    1462          80 :         m_poRealDriver = std::move(oIter->second);
    1463          80 :         poDriverManager->m_oMapRealDrivers.erase(oIter);
    1464             :     }
    1465             :     else
    1466             :     {
    1467             : #ifdef GDAL_NO_AUTOLOAD
    1468             :         return nullptr;
    1469             : #else
    1470        1258 :         CPLString osFuncName;
    1471         629 :         if (STARTS_WITH(m_osPluginFileName.c_str(), "gdal_"))
    1472             :         {
    1473         360 :             osFuncName = "GDALRegister_";
    1474         720 :             osFuncName += m_osPluginFileName.substr(
    1475             :                 strlen("gdal_"),
    1476         720 :                 m_osPluginFileName.find('.') - strlen("gdal_"));
    1477             :         }
    1478             :         else
    1479             :         {
    1480         269 :             CPLAssert(STARTS_WITH(m_osPluginFileName.c_str(), "ogr_"));
    1481         269 :             osFuncName = "RegisterOGR";
    1482         538 :             osFuncName += m_osPluginFileName.substr(
    1483         538 :                 strlen("ogr_"), m_osPluginFileName.find('.') - strlen("ogr_"));
    1484             :         }
    1485             : 
    1486         629 :         CPLErrorReset();
    1487         629 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    1488         629 :         void *pRegister = CPLGetSymbol(m_osPluginFullPath.c_str(), osFuncName);
    1489         629 :         CPLPopErrorHandler();
    1490         629 :         if (pRegister == nullptr)
    1491             :         {
    1492           0 :             CPLString osLastErrorMsg(CPLGetLastErrorMsg());
    1493           0 :             osFuncName = "GDALRegisterMe";
    1494           0 :             pRegister = CPLGetSymbol(m_osPluginFullPath.c_str(), osFuncName);
    1495           0 :             if (pRegister == nullptr)
    1496             :             {
    1497           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1498             :                          osLastErrorMsg.c_str());
    1499             :             }
    1500             :         }
    1501             : 
    1502         629 :         if (pRegister != nullptr)
    1503             :         {
    1504         629 :             CPLDebug("GDAL", "On-demand registering %s using %s.",
    1505             :                      m_osPluginFullPath.c_str(), osFuncName.c_str());
    1506             : 
    1507         629 :             poDriverManager->m_bInDeferredDriverLoading = true;
    1508             :             try
    1509             :             {
    1510         629 :                 reinterpret_cast<void (*)()>(pRegister)();
    1511             :             }
    1512           0 :             catch (...)
    1513             :             {
    1514           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "%s threw an exception",
    1515             :                          osFuncName.c_str());
    1516             :             }
    1517         629 :             poDriverManager->m_bInDeferredDriverLoading = false;
    1518             : 
    1519         629 :             oIter = poDriverManager->m_oMapRealDrivers.find(GetDescription());
    1520         629 :             if (oIter == poDriverManager->m_oMapRealDrivers.end())
    1521             :             {
    1522           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1523             :                          "Function %s of %s did not register a driver %s",
    1524             :                          osFuncName.c_str(), m_osPluginFullPath.c_str(),
    1525           0 :                          GetDescription());
    1526             :             }
    1527             :             else
    1528             :             {
    1529         629 :                 m_poRealDriver = std::move(oIter->second);
    1530         629 :                 poDriverManager->m_oMapRealDrivers.erase(oIter);
    1531             :             }
    1532             :         }
    1533             : #endif  // GDAL_NO_AUTOLOAD
    1534             :     }
    1535             : 
    1536         709 :     if (m_poRealDriver)
    1537             :     {
    1538         709 :         pfnDelete = m_poRealDriver->pfnDelete;
    1539         709 :         pfnRename = m_poRealDriver->pfnRename;
    1540         709 :         pfnCopyFiles = m_poRealDriver->pfnCopyFiles;
    1541             : 
    1542         709 :         if (strcmp(GetDescription(), m_poRealDriver->GetDescription()) != 0)
    1543             :         {
    1544           0 :             CPLError(
    1545             :                 CE_Warning, CPLE_AppDefined,
    1546             :                 "Driver %s has not the same name as its underlying driver (%s)",
    1547           0 :                 GetDescription(), m_poRealDriver->GetDescription());
    1548             :         }
    1549             : 
    1550       12264 :         for (const auto &osItem : m_oSetMetadataItems)
    1551             :         {
    1552       11555 :             const char *pszProxyValue = GetMetadataItem(osItem.c_str());
    1553             :             const char *pszRealValue =
    1554       11555 :                 m_poRealDriver->GetMetadataItem(osItem.c_str());
    1555       11555 :             if (pszProxyValue &&
    1556       11555 :                 (!pszRealValue || strcmp(pszProxyValue, pszRealValue) != 0))
    1557             :             {
    1558           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1559             :                          "Proxy driver %s declares %s whereas its real driver "
    1560             :                          "doesn't declare it or with a different value",
    1561           0 :                          GetDescription(), osItem.c_str());
    1562             :             }
    1563             :         }
    1564       14180 :         for (const char *pszListedItem : apszProxyMetadataItems)
    1565             :         {
    1566             :             const char *pszRealValue =
    1567       13471 :                 m_poRealDriver->GetMetadataItem(pszListedItem);
    1568       13471 :             if (pszRealValue)
    1569             :             {
    1570        5414 :                 const char *pszProxyValue = GetMetadataItem(pszListedItem);
    1571        5414 :                 if (!pszProxyValue || strcmp(pszProxyValue, pszRealValue) != 0)
    1572             :                 {
    1573           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1574             :                              "Driver %s declares %s whereas its proxy "
    1575             :                              "doesn't declare it or with a different value",
    1576           0 :                              GetDescription(), pszListedItem);
    1577             :                 }
    1578             :             }
    1579             :         }
    1580             : 
    1581             :         const auto CheckFunctionPointer =
    1582        1418 :             [this](void *pfnFuncProxy, void *pfnFuncReal, const char *pszFunc)
    1583             :         {
    1584        1418 :             if (pfnFuncReal && !pfnFuncProxy)
    1585             :             {
    1586           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1587             :                          "Driver %s declares a %s callback whereas its proxy "
    1588             :                          "does not declare it",
    1589           0 :                          GetDescription(), pszFunc);
    1590             :             }
    1591        1418 :             else if (!pfnFuncReal && pfnFuncProxy)
    1592             :             {
    1593           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1594             :                          "Proxy driver %s declares a %s callback whereas the "
    1595             :                          "real driver does not.",
    1596           0 :                          GetDescription(), pszFunc);
    1597             :             }
    1598        2127 :         };
    1599             : 
    1600         709 :         CheckFunctionPointer(
    1601         709 :             reinterpret_cast<void *>(m_poRealDriver->pfnIdentify),
    1602         709 :             reinterpret_cast<void *>(pfnIdentify), "pfnIdentify");
    1603             : 
    1604             :         // The real driver might provide a more accurate identification method
    1605         709 :         if (m_poRealDriver->pfnIdentify)
    1606         709 :             pfnIdentify = m_poRealDriver->pfnIdentify;
    1607             : 
    1608         709 :         CheckFunctionPointer(
    1609         709 :             reinterpret_cast<void *>(m_poRealDriver->pfnGetSubdatasetInfoFunc),
    1610         709 :             reinterpret_cast<void *>(pfnGetSubdatasetInfoFunc),
    1611             :             "pfnGetSubdatasetInfoFunc");
    1612             : 
    1613             :         const auto CheckFunctionPointerVersusCap =
    1614        5672 :             [this](void *pfnFunc, const char *pszFunc, const char *pszItemName)
    1615             :         {
    1616        2836 :             if (pfnFunc && !GetMetadataItem(pszItemName))
    1617             :             {
    1618           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1619             :                          "Driver %s declares a %s callback whereas its proxy "
    1620             :                          "does not declare %s",
    1621           0 :                          GetDescription(), pszFunc, pszItemName);
    1622             :             }
    1623        2836 :             else if (!pfnFunc && GetMetadataItem(pszItemName))
    1624             :             {
    1625           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1626             :                          "Proxy driver %s declares %s whereas the real "
    1627             :                          "driver does not declare a %s callback",
    1628           0 :                          GetDescription(), pszItemName, pszFunc);
    1629             :             }
    1630        3545 :         };
    1631             : 
    1632         709 :         CheckFunctionPointerVersusCap(
    1633         709 :             reinterpret_cast<void *>(m_poRealDriver->pfnOpen), "pfnOpen",
    1634             :             GDAL_DCAP_OPEN);
    1635         709 :         CheckFunctionPointerVersusCap(
    1636         709 :             reinterpret_cast<void *>(m_poRealDriver->pfnCreate), "pfnCreate",
    1637             :             GDAL_DCAP_CREATE);
    1638         709 :         CheckFunctionPointerVersusCap(
    1639         709 :             reinterpret_cast<void *>(m_poRealDriver->pfnCreateCopy),
    1640             :             "pfnCreateCopy", GDAL_DCAP_CREATECOPY);
    1641         709 :         CheckFunctionPointerVersusCap(
    1642         709 :             reinterpret_cast<void *>(m_poRealDriver->pfnCreateMultiDimensional),
    1643             :             "pfnCreateMultiDimensional", GDAL_DCAP_CREATE_MULTIDIMENSIONAL);
    1644             :     }
    1645             : 
    1646         709 :     return m_poRealDriver.get();
    1647             : }
    1648             : 
    1649             : /************************************************************************/
    1650             : /*                         GetPluginFullPath()                          */
    1651             : /************************************************************************/
    1652             : 
    1653       81399 : std::string GDALDriverManager::GetPluginFullPath(const char *pszFilename) const
    1654             : {
    1655       81399 :     if (!m_osLastTriedDirectory.empty())
    1656             :     {
    1657             :         std::string osFullFilename = CPLFormFilenameSafe(
    1658       79596 :             m_osLastTriedDirectory.c_str(), pszFilename, nullptr);
    1659             :         VSIStatBufL sStatBuf;
    1660       79596 :         if (VSIStatL(osFullFilename.c_str(), &sStatBuf) == 0)
    1661             :         {
    1662       79596 :             return osFullFilename;
    1663             :         }
    1664             :     }
    1665             : 
    1666             :     const char *pszGDAL_DRIVER_PATH =
    1667        1803 :         CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr);
    1668        1803 :     if (pszGDAL_DRIVER_PATH == nullptr)
    1669           0 :         pszGDAL_DRIVER_PATH = CPLGetConfigOption("OGR_DRIVER_PATH", nullptr);
    1670             : 
    1671             :     /* ---------------------------------------------------------------- */
    1672             :     /*      Allow applications to completely disable this search by     */
    1673             :     /*      setting the driver path to the special string "disable".    */
    1674             :     /* ---------------------------------------------------------------- */
    1675        1803 :     if (pszGDAL_DRIVER_PATH != nullptr && EQUAL(pszGDAL_DRIVER_PATH, "disable"))
    1676             :     {
    1677           0 :         CPLDebug("GDAL", "GDALDriverManager::GetPluginFullPath() disabled.");
    1678           0 :         return std::string();
    1679             :     }
    1680             : 
    1681             :     /* ---------------------------------------------------------------- */
    1682             :     /*      Where should we look for stuff?                             */
    1683             :     /* ---------------------------------------------------------------- */
    1684             :     const CPLStringList aosSearchPaths(
    1685        3606 :         GDALDriverManager::GetSearchPaths(pszGDAL_DRIVER_PATH));
    1686             : 
    1687             :     /* ---------------------------------------------------------------- */
    1688             :     /*      Format the ABI version specific subdirectory to look in.    */
    1689             :     /* ---------------------------------------------------------------- */
    1690        3606 :     CPLString osABIVersion;
    1691             : 
    1692        1803 :     osABIVersion.Printf("%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
    1693             : 
    1694             :     /* ---------------------------------------------------------------- */
    1695             :     /*      Scan each directory looking for the file of interest.       */
    1696             :     /* ---------------------------------------------------------------- */
    1697        1803 :     const int nSearchPaths = aosSearchPaths.size();
    1698        1803 :     for (int iDir = 0; iDir < nSearchPaths; ++iDir)
    1699             :     {
    1700             :         std::string osABISpecificDir =
    1701        1803 :             CPLFormFilenameSafe(aosSearchPaths[iDir], osABIVersion, nullptr);
    1702             : 
    1703             :         VSIStatBufL sStatBuf;
    1704        1803 :         if (VSIStatL(osABISpecificDir.c_str(), &sStatBuf) != 0)
    1705        1803 :             osABISpecificDir = aosSearchPaths[iDir];
    1706             : 
    1707             :         std::string osFullFilename =
    1708        1803 :             CPLFormFilenameSafe(osABISpecificDir.c_str(), pszFilename, nullptr);
    1709        1803 :         if (VSIStatL(osFullFilename.c_str(), &sStatBuf) == 0)
    1710             :         {
    1711        1803 :             m_osLastTriedDirectory = std::move(osABISpecificDir);
    1712        1803 :             return osFullFilename;
    1713             :         }
    1714             :     }
    1715             : 
    1716           0 :     return std::string();
    1717             : }
    1718             : 
    1719             : /************************************************************************/
    1720             : /*                    DeclareDeferredPluginDriver()                     */
    1721             : /************************************************************************/
    1722             : 
    1723             : /** Declare a driver that will be loaded as a plugin, when actually needed.
    1724             :  *
    1725             :  * @param poProxyDriver Plugin driver proxy
    1726             :  *
    1727             :  * @since 3.9
    1728             :  */
    1729       79332 : void GDALDriverManager::DeclareDeferredPluginDriver(
    1730             :     GDALPluginDriverProxy *poProxyDriver)
    1731             : {
    1732       79332 :     CPLMutexHolderD(&hDMMutex);
    1733             : 
    1734       79332 :     const auto &osPluginFileName = poProxyDriver->GetPluginFileName();
    1735       79332 :     const char *pszPluginFileName = osPluginFileName.c_str();
    1736       79332 :     if ((!STARTS_WITH(pszPluginFileName, "gdal_") &&
    1737       27045 :          !STARTS_WITH(pszPluginFileName, "ogr_")) ||
    1738       79332 :         !strchr(pszPluginFileName, '.'))
    1739             :     {
    1740           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid plugin filename: %s",
    1741             :                  pszPluginFileName);
    1742           0 :         return;
    1743             :     }
    1744             : 
    1745       79332 :     if (GDALGetDriverByName(poProxyDriver->GetDescription()))
    1746             :     {
    1747           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1748             :                  "DeclarePluginDriver(): trying to register %s several times",
    1749           0 :                  poProxyDriver->GetDescription());
    1750           0 :         delete poProxyDriver;
    1751           0 :         return;
    1752             :     }
    1753             : 
    1754       79332 :     const std::string osFullPath = GetPluginFullPath(pszPluginFileName);
    1755       79332 :     poProxyDriver->SetPluginFullPath(osFullPath);
    1756             : 
    1757       79332 :     if (osFullPath.empty())
    1758             :     {
    1759             :         // Do not try to re-register a non-existent deferred plugin
    1760             :         // This would cause memory leaks in case of repeated calls to GDALAllRegister()
    1761             :         // Cf https://github.com/rasterio/rasterio/issues/3250
    1762           0 :         for (const auto &poDriver : m_aoHiddenDrivers)
    1763             :         {
    1764           0 :             if (EQUAL(poDriver->GetDescription(),
    1765             :                       poProxyDriver->GetDescription()))
    1766             :             {
    1767           0 :                 delete poProxyDriver;
    1768           0 :                 return;
    1769             :             }
    1770             :         }
    1771             : 
    1772           0 :         CPLDebug("GDAL",
    1773             :                  "Proxy driver %s *not* registered due to %s not being found",
    1774           0 :                  poProxyDriver->GetDescription(), pszPluginFileName);
    1775           0 :         RegisterDriver(poProxyDriver, /*bHidden=*/true);
    1776             :     }
    1777             :     else
    1778             :     {
    1779             :         //CPLDebugOnly("GDAL", "Registering proxy driver %s",
    1780             :         //             poProxyDriver->GetDescription());
    1781       79332 :         RegisterDriver(poProxyDriver);
    1782       79332 :         m_oSetPluginFileNames.insert(pszPluginFileName);
    1783             :     }
    1784             : }
    1785             : 
    1786             : /************************************************************************/
    1787             : /*                      GDALDestroyDriverManager()                      */
    1788             : /************************************************************************/
    1789             : 
    1790             : /**
    1791             :  * \brief Destroy the driver manager.
    1792             :  *
    1793             :  * Incidentally unloads all managed drivers.
    1794             :  *
    1795             :  * NOTE: This function is not thread safe.  It should not be called while
    1796             :  * other threads are actively using GDAL.
    1797             :  *
    1798             :  * \see GDALDestroy()
    1799             :  * \deprecated Use GDALDestroy() instead
    1800             :  */
    1801             : 
    1802        1807 : void CPL_STDCALL GDALDestroyDriverManager(void)
    1803             : 
    1804             : {
    1805             :     // THREADSAFETY: We would like to lock the mutex here, but it
    1806             :     // needs to be reacquired within the destructor during driver
    1807             :     // deregistration.
    1808             : 
    1809             :     // FIXME: Disable following code as it crashed on OSX CI test.
    1810             :     // std::lock_guard<std::mutex> oLock(oDeleteMutex);
    1811             : 
    1812        1807 :     if (poDM != nullptr)
    1813             :     {
    1814        1136 :         delete poDM;
    1815        1136 :         poDM = nullptr;
    1816             :     }
    1817        1807 : }

Generated by: LCOV version 1.14