LCOV - code coverage report
Current view: top level - gcore - gdaldrivermanager.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 438 550 79.6 %
Date: 2024-05-04 12:52:34 Functions: 39 41 95.1 %

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

Generated by: LCOV version 1.14