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

Generated by: LCOV version 1.14