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