Coverage Report

Created: 2025-06-13 06:29

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