mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 06:06:00 -06:00
846 lines
31 KiB
C++
846 lines
31 KiB
C++
/******************************************************************************
|
|
* $Id: gdaldrivermanager.cpp 29330 2015-06-14 12:11:11Z rouault $
|
|
*
|
|
* Project: GDAL Core
|
|
* Purpose: Implementation of GDALDriverManager class.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 1998, Frank Warmerdam
|
|
* Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "gdal_priv.h"
|
|
#include "cpl_string.h"
|
|
#include "cpl_multiproc.h"
|
|
#include "ogr_srs_api.h"
|
|
#include "cpl_multiproc.h"
|
|
#include "gdal_pam.h"
|
|
#include "gdal_alg_priv.h"
|
|
|
|
#ifdef _MSC_VER
|
|
# ifdef MSVC_USE_VLD
|
|
# include <wchar.h>
|
|
# include <vld.h>
|
|
# endif
|
|
#endif
|
|
|
|
CPL_CVSID("$Id: gdaldrivermanager.cpp 29330 2015-06-14 12:11:11Z rouault $");
|
|
|
|
static const char *pszUpdatableINST_DATA =
|
|
"__INST_DATA_TARGET: ";
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* GDALDriverManager */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
static volatile GDALDriverManager *poDM = NULL;
|
|
static CPLMutex *hDMMutex = NULL;
|
|
|
|
CPLMutex** GDALGetphDMMutex() { return &hDMMutex; }
|
|
|
|
/************************************************************************/
|
|
/* GetGDALDriverManager() */
|
|
/* */
|
|
/* A freestanding function to get the only instance of the */
|
|
/* GDALDriverManager. */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Fetch the global GDAL driver manager.
|
|
*
|
|
* This function fetches the pointer to the singleton global driver manager.
|
|
* If the driver manager doesn't exist it is automatically created.
|
|
*
|
|
* @return pointer to the global driver manager. This should not be able
|
|
* to fail.
|
|
*/
|
|
|
|
GDALDriverManager * GetGDALDriverManager()
|
|
|
|
{
|
|
if( poDM == NULL )
|
|
{
|
|
CPLMutexHolderD( &hDMMutex );
|
|
|
|
if( poDM == NULL )
|
|
poDM = new GDALDriverManager();
|
|
}
|
|
|
|
CPLAssert( NULL != poDM );
|
|
|
|
return const_cast<GDALDriverManager *>( poDM );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALDriverManager() */
|
|
/************************************************************************/
|
|
|
|
GDALDriverManager::GDALDriverManager()
|
|
|
|
{
|
|
nDrivers = 0;
|
|
papoDrivers = NULL;
|
|
|
|
CPLAssert( poDM == NULL );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* We want to push a location to search for data files */
|
|
/* supporting GDAL/OGR such as EPSG csv files, S-57 definition */
|
|
/* files, and so forth. The static pszUpdateableINST_DATA */
|
|
/* string can be updated within the shared library or */
|
|
/* executable during an install to point installed data */
|
|
/* directory. If it isn't burned in here then we use the */
|
|
/* INST_DATA macro (setup at configure time) if */
|
|
/* available. Otherwise we don't push anything and we hope */
|
|
/* other mechanisms such as environment variables will have */
|
|
/* been employed. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( CPLGetConfigOption( "GDAL_DATA", NULL ) != NULL )
|
|
{
|
|
// this one is picked up automatically by finder initialization.
|
|
}
|
|
else if( pszUpdatableINST_DATA[19] != ' ' )
|
|
{
|
|
CPLPushFinderLocation( pszUpdatableINST_DATA + 19 );
|
|
}
|
|
else
|
|
{
|
|
#ifdef INST_DATA
|
|
CPLPushFinderLocation( INST_DATA );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~GDALDriverManager() */
|
|
/************************************************************************/
|
|
|
|
void GDALDatasetPoolPreventDestroy(); /* keep that in sync with gdalproxypool.cpp */
|
|
void GDALDatasetPoolForceDestroy(); /* keep that in sync with gdalproxypool.cpp */
|
|
|
|
GDALDriverManager::~GDALDriverManager()
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup any open datasets. */
|
|
/* -------------------------------------------------------------------- */
|
|
int i, nDSCount;
|
|
GDALDataset **papoDSList;
|
|
|
|
/* First begin by requesting each reamining dataset to drop any reference */
|
|
/* to other datasets */
|
|
int bHasDroppedRef;
|
|
|
|
/* We have to prevent the destroying of the dataset pool during this first */
|
|
/* phase, otherwise it cause crashes with a VRT B referencing a VRT A, and if */
|
|
/* CloseDependentDatasets() is called first on VRT A. */
|
|
/* If we didn't do this nasty trick, due to the refCountOfDisableRefCount */
|
|
/* mechanism that cheats the real refcount of the dataset pool, we might */
|
|
/* destroy the dataset pool too early, leading the VRT A to */
|
|
/* destroy itself indirectly ... Ok, I am aware this explanation does */
|
|
/* not make any sense unless you try it under a debugger ... */
|
|
/* When people just manipulate "top-level" dataset handles, we luckily */
|
|
/* don't need this horrible hack, but GetOpenDatasets() expose "low-level" */
|
|
/* datasets, which defeat some "design" of the proxy pool */
|
|
GDALDatasetPoolPreventDestroy();
|
|
|
|
do
|
|
{
|
|
papoDSList = GDALDataset::GetOpenDatasets(&nDSCount);
|
|
/* If a dataset has dropped a reference, the list might have become */
|
|
/* invalid, so go out of the loop and try again with the new valid */
|
|
/* list */
|
|
bHasDroppedRef = FALSE;
|
|
for(i=0;i<nDSCount && !bHasDroppedRef;i++)
|
|
{
|
|
//CPLDebug("GDAL", "Call CloseDependentDatasets() on %s",
|
|
// papoDSList[i]->GetDescription() );
|
|
bHasDroppedRef = papoDSList[i]->CloseDependentDatasets();
|
|
}
|
|
} while(bHasDroppedRef);
|
|
|
|
/* Now let's destroy the dataset pool. Nobody should use it afterwards */
|
|
/* if people have well released their dependent datasets above */
|
|
GDALDatasetPoolForceDestroy();
|
|
|
|
/* Now close the stand-alone datasets */
|
|
papoDSList = GDALDataset::GetOpenDatasets(&nDSCount);
|
|
for(i=0;i<nDSCount;i++)
|
|
{
|
|
CPLDebug( "GDAL", "force close of %s (%p) in GDALDriverManager cleanup.",
|
|
papoDSList[i]->GetDescription(), papoDSList[i] );
|
|
/* Destroy with delete operator rather than GDALClose() to force deletion of */
|
|
/* datasets with multiple reference count */
|
|
/* We could also iterate while GetOpenDatasets() returns a non NULL list */
|
|
delete papoDSList[i];
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Destroy the existing drivers. */
|
|
/* -------------------------------------------------------------------- */
|
|
while( GetDriverCount() > 0 )
|
|
{
|
|
GDALDriver *poDriver = GetDriver(0);
|
|
|
|
DeregisterDriver(poDriver);
|
|
delete poDriver;
|
|
}
|
|
|
|
delete GDALGetAPIPROXYDriver();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup local memory. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSIFree( papoDrivers );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup any Proxy related memory. */
|
|
/* -------------------------------------------------------------------- */
|
|
PamCleanProxyDB();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Blow away all the finder hints paths. We really shouldn't */
|
|
/* be doing all of them, but it is currently hard to keep track */
|
|
/* of those that actually belong to us. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLFinderClean();
|
|
CPLFreeConfig();
|
|
CPLCleanupSharedFileMutex();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup any memory allocated by the OGRSpatialReference */
|
|
/* related subsystem. */
|
|
/* -------------------------------------------------------------------- */
|
|
OSRCleanup();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup VSIFileManager. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSICleanupFileManager();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup thread local storage ... I hope the program is all */
|
|
/* done with GDAL/OGR! */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLCleanupTLS();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup our mutex. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( hDMMutex )
|
|
{
|
|
CPLDestroyMutex( hDMMutex );
|
|
hDMMutex = NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup dataset list mutex */
|
|
/* -------------------------------------------------------------------- */
|
|
if ( *GDALGetphDLMutex() != NULL )
|
|
{
|
|
CPLDestroyMutex( *GDALGetphDLMutex() );
|
|
*GDALGetphDLMutex() = NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup raster block mutex */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALRasterBlock::DestroyRBMutex();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup gdaltransformer.cpp mutex */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALCleanupTransformDeserializerMutex();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup cpl_error.cpp mutex */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLCleanupErrorMutex();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup CPLsetlocale mutex */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLCleanupSetlocaleMutex();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup the master CPL mutex, which governs the creation */
|
|
/* of all other mutexes. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLCleanupMasterMutex();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Ensure the global driver manager pointer is NULLed out. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poDM == this )
|
|
poDM = NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetDriverCount() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Fetch the number of registered drivers.
|
|
*
|
|
* This C analog to this is GDALGetDriverCount().
|
|
*
|
|
* @return the number of registered drivers.
|
|
*/
|
|
|
|
int GDALDriverManager::GetDriverCount()
|
|
|
|
{
|
|
return( nDrivers );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALGetDriverCount() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Fetch the number of registered drivers.
|
|
*
|
|
* @see GDALDriverManager::GetDriverCount()
|
|
*/
|
|
|
|
int CPL_STDCALL GDALGetDriverCount()
|
|
|
|
{
|
|
return GetGDALDriverManager()->GetDriverCount();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetDriver() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Fetch driver by index.
|
|
*
|
|
* This C analog to this is GDALGetDriver().
|
|
*
|
|
* @param iDriver the driver index from 0 to GetDriverCount()-1.
|
|
*
|
|
* @return the driver identified by the index or NULL if the index is invalid
|
|
*/
|
|
|
|
GDALDriver * GDALDriverManager::GetDriver( int iDriver )
|
|
|
|
{
|
|
CPLMutexHolderD( &hDMMutex );
|
|
|
|
return GetDriver_unlocked(iDriver);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALGetDriver() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Fetch driver by index.
|
|
*
|
|
* @see GDALDriverManager::GetDriver()
|
|
*/
|
|
|
|
GDALDriverH CPL_STDCALL GDALGetDriver( int iDriver )
|
|
|
|
{
|
|
return (GDALDriverH) GetGDALDriverManager()->GetDriver(iDriver);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* RegisterDriver() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Register a driver for use.
|
|
*
|
|
* The C analog is GDALRegisterDriver().
|
|
*
|
|
* Normally this method is used by format specific C callable registration
|
|
* entry points such as GDALRegister_GTiff() rather than being called
|
|
* directly by application level code.
|
|
*
|
|
* If this driver (based on the object pointer, not short name) is already
|
|
* registered, then no change is made, and the index of the existing driver
|
|
* is returned. Otherwise the driver list is extended, and the new driver
|
|
* is added at the end.
|
|
*
|
|
* @param poDriver the driver to register.
|
|
*
|
|
* @return the index of the new installed driver.
|
|
*/
|
|
|
|
int GDALDriverManager::RegisterDriver( GDALDriver * poDriver )
|
|
|
|
{
|
|
CPLMutexHolderD( &hDMMutex );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If it is already registered, just return the existing */
|
|
/* index. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( GetDriverByName_unlocked( poDriver->GetDescription() ) != NULL )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < nDrivers; i++ )
|
|
{
|
|
if( papoDrivers[i] == poDriver )
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
CPLAssert( FALSE );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Otherwise grow the list to hold the new entry. */
|
|
/* -------------------------------------------------------------------- */
|
|
papoDrivers = (GDALDriver **)
|
|
VSIRealloc(papoDrivers, sizeof(GDALDriver *) * (nDrivers+1));
|
|
|
|
papoDrivers[nDrivers] = poDriver;
|
|
nDrivers++;
|
|
|
|
if( poDriver->pfnOpen != NULL ||
|
|
poDriver->pfnOpenWithDriverArg != NULL )
|
|
poDriver->SetMetadataItem( GDAL_DCAP_OPEN, "YES" );
|
|
|
|
if( poDriver->pfnCreate != NULL )
|
|
poDriver->SetMetadataItem( GDAL_DCAP_CREATE, "YES" );
|
|
|
|
if( poDriver->pfnCreateCopy != NULL )
|
|
poDriver->SetMetadataItem( GDAL_DCAP_CREATECOPY, "YES" );
|
|
|
|
/* Backward compability for GDAL raster out-of-tree drivers: */
|
|
/* if a driver hasn't explicitly set a vector capability, assume it is */
|
|
/* a raster driver (legacy OGR drivers will have DCAP_VECTOR set before */
|
|
/* calling RegisterDriver() ) */
|
|
if( poDriver->GetMetadataItem( GDAL_DCAP_RASTER ) == NULL &&
|
|
poDriver->GetMetadataItem( GDAL_DCAP_VECTOR ) == NULL )
|
|
{
|
|
CPLDebug("GDAL", "Assuming DCAP_RASTER for driver %s. Please fix it.",
|
|
poDriver->GetDescription() );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
}
|
|
|
|
if( poDriver->GetMetadataItem( GDAL_DMD_OPENOPTIONLIST ) != NULL &&
|
|
poDriver->pfnIdentify == NULL &&
|
|
!EQUALN(poDriver->GetDescription(), "Interlis", strlen("Interlis")) )
|
|
{
|
|
CPLDebug("GDAL", "Driver %s that defines GDAL_DMD_OPENOPTIONLIST must also "
|
|
"implement Identify(), so that it can be used",
|
|
poDriver->GetDescription() );
|
|
}
|
|
|
|
oMapNameToDrivers[CPLString(poDriver->GetDescription()).toupper()] = poDriver;
|
|
|
|
int iResult = nDrivers - 1;
|
|
|
|
return iResult;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegisterDriver() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Register a driver for use.
|
|
*
|
|
* @see GDALDriverManager::GetRegisterDriver()
|
|
*/
|
|
|
|
int CPL_STDCALL GDALRegisterDriver( GDALDriverH hDriver )
|
|
|
|
{
|
|
VALIDATE_POINTER1( hDriver, "GDALRegisterDriver", 0 );
|
|
|
|
return GetGDALDriverManager()->RegisterDriver( (GDALDriver *) hDriver );
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* DeregisterDriver() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Deregister the passed driver.
|
|
*
|
|
* If the driver isn't found no change is made.
|
|
*
|
|
* The C analog is GDALDeregisterDriver().
|
|
*
|
|
* @param poDriver the driver to deregister.
|
|
*/
|
|
|
|
void GDALDriverManager::DeregisterDriver( GDALDriver * poDriver )
|
|
|
|
{
|
|
int i;
|
|
CPLMutexHolderD( &hDMMutex );
|
|
|
|
for( i = 0; i < nDrivers; i++ )
|
|
{
|
|
if( papoDrivers[i] == poDriver )
|
|
break;
|
|
}
|
|
|
|
if( i == nDrivers )
|
|
return;
|
|
|
|
oMapNameToDrivers.erase(CPLString(poDriver->GetDescription()).toupper());
|
|
while( i < nDrivers-1 )
|
|
{
|
|
papoDrivers[i] = papoDrivers[i+1];
|
|
i++;
|
|
}
|
|
nDrivers--;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALDeregisterDriver() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Deregister the passed driver.
|
|
*
|
|
* @see GDALDriverManager::GetDeregisterDriver()
|
|
*/
|
|
|
|
void CPL_STDCALL GDALDeregisterDriver( GDALDriverH hDriver )
|
|
|
|
{
|
|
VALIDATE_POINTER0( hDriver, "GDALDeregisterDriver" );
|
|
|
|
GetGDALDriverManager()->DeregisterDriver( (GDALDriver *) hDriver );
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* GetDriverByName() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Fetch a driver based on the short name.
|
|
*
|
|
* The C analog is the GDALGetDriverByName() function.
|
|
*
|
|
* @param pszName the short name, such as GTiff, being searched for.
|
|
*
|
|
* @return the identified driver, or NULL if no match is found.
|
|
*/
|
|
|
|
GDALDriver * GDALDriverManager::GetDriverByName( const char * pszName )
|
|
|
|
{
|
|
CPLMutexHolderD( &hDMMutex );
|
|
|
|
return oMapNameToDrivers[CPLString(pszName).toupper()];
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALGetDriverByName() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Fetch a driver based on the short name.
|
|
*
|
|
* @see GDALDriverManager::GetDriverByName()
|
|
*/
|
|
|
|
GDALDriverH CPL_STDCALL GDALGetDriverByName( const char * pszName )
|
|
|
|
{
|
|
VALIDATE_POINTER1( pszName, "GDALGetDriverByName", NULL );
|
|
|
|
return( GetGDALDriverManager()->GetDriverByName( pszName ) );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AutoSkipDrivers() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief This method unload undesirable drivers.
|
|
*
|
|
* All drivers specified in the comma delimited list in the GDAL_SKIP
|
|
* environment variable) will be deregistered and destroyed. This method
|
|
* should normally be called after registration of standard drivers to allow
|
|
* the user a way of unloading undesired drivers. The GDALAllRegister()
|
|
* function already invokes AutoSkipDrivers() at the end, so if that functions
|
|
* is called, it should not be necessary to call this method from application
|
|
* code.
|
|
*
|
|
* Note: space separator is also accepted for backward compatibility, but some
|
|
* vector formats have spaces in their names, so it is encouraged to use comma
|
|
* to avoid issues.
|
|
*/
|
|
|
|
void GDALDriverManager::AutoSkipDrivers()
|
|
|
|
{
|
|
char **apapszList[2] = { NULL, NULL };
|
|
const char* pszGDAL_SKIP = CPLGetConfigOption( "GDAL_SKIP", NULL );
|
|
if( pszGDAL_SKIP != NULL )
|
|
{
|
|
/* Favour comma as a separator. If not found, then use space */
|
|
const char* pszSep = (strchr(pszGDAL_SKIP, ',') != NULL) ? "," : " ";
|
|
apapszList[0] = CSLTokenizeStringComplex( pszGDAL_SKIP, pszSep, FALSE, FALSE);
|
|
}
|
|
const char* pszOGR_SKIP = CPLGetConfigOption( "OGR_SKIP", NULL );
|
|
if( pszOGR_SKIP != NULL )
|
|
{
|
|
/* OGR has always used comma as a separator */
|
|
apapszList[1] = CSLTokenizeStringComplex(pszOGR_SKIP, ",", FALSE, FALSE);
|
|
}
|
|
|
|
for( int j = 0; j < 2; j++ )
|
|
{
|
|
for( int i = 0; apapszList[j] != NULL && apapszList[j][i] != NULL; i++ )
|
|
{
|
|
GDALDriver *poDriver = GetDriverByName( apapszList[j][i] );
|
|
|
|
if( poDriver == NULL )
|
|
CPLError( CE_Warning, CPLE_AppDefined,
|
|
"Unable to find driver %s to unload from GDAL_SKIP environment variable.",
|
|
apapszList[j][i] );
|
|
else
|
|
{
|
|
CPLDebug( "GDAL", "AutoSkipDriver(%s)", apapszList[j][i] );
|
|
DeregisterDriver( poDriver );
|
|
delete poDriver;
|
|
}
|
|
}
|
|
}
|
|
|
|
CSLDestroy( apapszList[0] );
|
|
CSLDestroy( apapszList[1] );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AutoLoadDrivers() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Auto-load GDAL drivers from shared libraries.
|
|
*
|
|
* This function will automatically load drivers from shared libraries. It
|
|
* searches the "driver path" for .so (or .dll) files that start with the
|
|
* prefix "gdal_X.so". It then tries to load them and then tries to call a
|
|
* function within them called GDALRegister_X() where the 'X' is the same as
|
|
* the remainder of the shared library basename ('X' is case sensitive), or
|
|
* failing that to call GDALRegisterMe().
|
|
*
|
|
* There are a few rules for the driver path. If the GDAL_DRIVER_PATH
|
|
* environment variable it set, it is taken to be a list of directories to
|
|
* search separated by colons on UNIX, or semi-colons on Windows. Otherwise
|
|
* the /usr/local/lib/gdalplugins directory, and (if known) the
|
|
* lib/gdalplugins subdirectory of the gdal home directory are searched on
|
|
* UNIX and $(BINDIR)\gdalplugins on Windows.
|
|
*
|
|
* Auto loading can be completely disabled by setting the GDAL_DRIVER_PATH
|
|
* config option to "disable".
|
|
*/
|
|
|
|
void GDALDriverManager::AutoLoadDrivers()
|
|
|
|
{
|
|
char **papszSearchPath = NULL;
|
|
const char *pszGDAL_DRIVER_PATH =
|
|
CPLGetConfigOption( "GDAL_DRIVER_PATH", NULL );
|
|
if( pszGDAL_DRIVER_PATH == NULL )
|
|
pszGDAL_DRIVER_PATH = CPLGetConfigOption( "OGR_DRIVER_PATH", NULL );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Allow applications to completely disable this search by */
|
|
/* setting the driver path to the special string "disable". */
|
|
/* -------------------------------------------------------------------- */
|
|
if( pszGDAL_DRIVER_PATH != NULL && EQUAL(pszGDAL_DRIVER_PATH,"disable"))
|
|
{
|
|
CPLDebug( "GDAL", "GDALDriverManager::AutoLoadDrivers() disabled." );
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Where should we look for stuff? */
|
|
/* -------------------------------------------------------------------- */
|
|
if( pszGDAL_DRIVER_PATH != NULL )
|
|
{
|
|
#ifdef WIN32
|
|
papszSearchPath =
|
|
CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ";", TRUE, FALSE );
|
|
#else
|
|
papszSearchPath =
|
|
CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ":", TRUE, FALSE );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef GDAL_PREFIX
|
|
papszSearchPath = CSLAddString( papszSearchPath,
|
|
#ifdef MACOSX_FRAMEWORK
|
|
GDAL_PREFIX "/PlugIns");
|
|
#else
|
|
GDAL_PREFIX "/lib/gdalplugins" );
|
|
#endif
|
|
#else
|
|
char szExecPath[1024];
|
|
|
|
if( CPLGetExecPath( szExecPath, sizeof(szExecPath) ) )
|
|
{
|
|
char szPluginDir[sizeof(szExecPath)+50];
|
|
strcpy( szPluginDir, CPLGetDirname( szExecPath ) );
|
|
strcat( szPluginDir, "\\gdalplugins" );
|
|
papszSearchPath = CSLAddString( papszSearchPath, szPluginDir );
|
|
}
|
|
else
|
|
{
|
|
papszSearchPath = CSLAddString( papszSearchPath,
|
|
"/usr/local/lib/gdalplugins" );
|
|
}
|
|
#endif
|
|
|
|
#ifdef MACOSX_FRAMEWORK
|
|
#define num2str(x) str(x)
|
|
#define str(x) #x
|
|
papszSearchPath = CSLAddString( papszSearchPath,
|
|
"/Library/Application Support/GDAL/"
|
|
num2str(GDAL_VERSION_MAJOR) "."
|
|
num2str(GDAL_VERSION_MINOR) "/PlugIns" );
|
|
#endif
|
|
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Format the ABI version specific subdirectory to look in. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLString osABIVersion;
|
|
|
|
osABIVersion.Printf( "%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Scan each directory looking for files starting with gdal_ */
|
|
/* -------------------------------------------------------------------- */
|
|
for( int iDir = 0; iDir < CSLCount(papszSearchPath); iDir++ )
|
|
{
|
|
char **papszFiles = NULL;
|
|
VSIStatBufL sStatBuf;
|
|
CPLString osABISpecificDir =
|
|
CPLFormFilename( papszSearchPath[iDir], osABIVersion, NULL );
|
|
|
|
if( VSIStatL( osABISpecificDir, &sStatBuf ) != 0 )
|
|
osABISpecificDir = papszSearchPath[iDir];
|
|
|
|
papszFiles = CPLReadDir( osABISpecificDir );
|
|
int nFileCount = CSLCount(papszFiles);
|
|
|
|
for( int iFile = 0; iFile < nFileCount; iFile++ )
|
|
{
|
|
char *pszFuncName;
|
|
const char *pszFilename;
|
|
const char *pszExtension = CPLGetExtension( papszFiles[iFile] );
|
|
void *pRegister;
|
|
|
|
if( !EQUAL(pszExtension,"dll")
|
|
&& !EQUAL(pszExtension,"so")
|
|
&& !EQUAL(pszExtension,"dylib") )
|
|
continue;
|
|
|
|
if( EQUALN(papszFiles[iFile],"gdal_",strlen("gdal_")) )
|
|
{
|
|
pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
|
|
sprintf( pszFuncName, "GDALRegister_%s",
|
|
CPLGetBasename(papszFiles[iFile]) + strlen("gdal_") );
|
|
}
|
|
else if ( EQUALN(papszFiles[iFile],"ogr_",strlen("ogr_")) )
|
|
{
|
|
pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
|
|
sprintf( pszFuncName, "RegisterOGR%s",
|
|
CPLGetBasename(papszFiles[iFile]) + strlen("ogr_") );
|
|
}
|
|
else
|
|
continue;
|
|
|
|
pszFilename =
|
|
CPLFormFilename( osABISpecificDir,
|
|
papszFiles[iFile], NULL );
|
|
|
|
CPLErrorReset();
|
|
CPLPushErrorHandler(CPLQuietErrorHandler);
|
|
pRegister = CPLGetSymbol( pszFilename, pszFuncName );
|
|
CPLPopErrorHandler();
|
|
if( pRegister == NULL )
|
|
{
|
|
CPLString osLastErrorMsg(CPLGetLastErrorMsg());
|
|
strcpy( pszFuncName, "GDALRegisterMe" );
|
|
pRegister = CPLGetSymbol( pszFilename, pszFuncName );
|
|
if( pRegister == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"%s", osLastErrorMsg.c_str() );
|
|
}
|
|
}
|
|
|
|
if( pRegister != NULL )
|
|
{
|
|
CPLDebug( "GDAL", "Auto register %s using %s.",
|
|
pszFilename, pszFuncName );
|
|
|
|
((void (*)()) pRegister)();
|
|
}
|
|
|
|
CPLFree( pszFuncName );
|
|
}
|
|
|
|
CSLDestroy( papszFiles );
|
|
}
|
|
|
|
CSLDestroy( papszSearchPath );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALDestroyDriverManager() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Destroy the driver manager.
|
|
*
|
|
* Incidently unloads all managed drivers.
|
|
*
|
|
* NOTE: This function is not thread safe. It should not be called while
|
|
* other threads are actively using GDAL.
|
|
*/
|
|
|
|
void CPL_STDCALL GDALDestroyDriverManager( void )
|
|
|
|
{
|
|
// THREADSAFETY: We would like to lock the mutex here, but it
|
|
// needs to be reacquired within the destructor during driver
|
|
// deregistration.
|
|
if( poDM != NULL )
|
|
delete poDM;
|
|
}
|
|
|
|
|