Coverage Report

Created: 2026-02-14 06:52

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