LCOV - code coverage report
Current view: top level - gcore - gdaldrivermanager.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 437 559 78.2 %
Date: 2025-01-18 12:42:00 Functions: 40 42 95.2 %

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

Generated by: LCOV version 1.14