root/tags/gdal_1_3_2/gcore/gdaldrivermanager.cpp

Revision 9398, 23.3 kB (checked in by fwarmerdam, 3 years ago)

updated contact info

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  GDAL Core
5  * Purpose:  Implementation of GDALDriverManager class.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1998, Frank Warmerdam
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  * $Log$
31  * Revision 1.32  2006/03/28 14:49:56  fwarmerdam
32  * updated contact info
33  *
34  * Revision 1.31  2005/09/15 18:39:43  fwarmerdam
35  * cleanup TLS and VSI with driver manager
36  *
37  * Revision 1.30  2005/07/11 17:29:48  fwarmerdam
38  * More use of mutex in some "read" cases.
39  *
40  * Revision 1.29  2005/07/11 17:25:49  fwarmerdam
41  * Fixed minior race condition in GDALDriverManager creation.
42  *
43  * Revision 1.28  2005/07/11 17:17:21  fwarmerdam
44  * Added note on thread un-safety of GDALDestroyDriverManager.
45  *
46  * Revision 1.27  2005/07/11 17:15:32  fwarmerdam
47  * Grab mutex to create drive manager
48  *
49  * Revision 1.26  2005/06/10 15:37:35  fwarmerdam
50  * avoid use of MAX_PATH
51  *
52  * Revision 1.25  2005/06/10 14:59:12  fwarmerdam
53  * Added option to search under executable directory for plugins on win32.
54  *
55  * Revision 1.24  2005/05/23 06:46:24  fwarmerdam
56  * added mutex to protect driver manager
57  *
58  * Revision 1.23  2005/04/04 15:24:48  fwarmerdam
59  * Most C entry points now CPL_STDCALL
60  *
61  * Revision 1.22  2005/01/19 20:27:17  fwarmerdam
62  * Search in lib/gdalplugins instead of directly in lib directory.
63  * Only try files endning in .dll, .so or .dylib.  see bug 746
64  *
65  * Revision 1.21  2004/11/22 16:01:29  fwarmerdam
66  * added GDAL_PREFIX
67  *
68  * Revision 1.20  2004/09/23 16:21:32  fwarmerdam
69  * added call to OSRCleanup()
70  *
71  * Revision 1.19  2004/04/29 19:14:27  warmerda
72  * Avoid extra newline when autoregistering.
73  *
74  * Revision 1.18  2004/04/16 06:23:46  warmerda
75  * Use CPLGetConfigOption() instead of getenv().
76  *
77  * Revision 1.17  2003/12/28 17:27:36  warmerda
78  * added call to CPLFreeConfig()
79  *
80  * Revision 1.16  2003/05/20 19:10:36  warmerda
81  * added GDAL_DATA and CPLGetConfigOptions support
82  *
83  * Revision 1.15  2003/04/30 17:13:48  warmerda
84  * added docs for many C functions
85  */
86
87 #include "gdal_priv.h"
88 #include "cpl_string.h"
89 #include "cpl_multiproc.h"
90 #include "ogr_srs_api.h"
91 #include "cpl_multiproc.h"
92
93 CPL_CVSID("$Id$");
94
95 static const char *pszUpdatableINST_DATA =
96 "__INST_DATA_TARGET:                                                                                                                                      ";
97
98 /************************************************************************/
99 /* ==================================================================== */
100 /*                           GDALDriverManager                          */
101 /* ==================================================================== */
102 /************************************************************************/
103
104 static volatile GDALDriverManager        *poDM = NULL;
105 static void *hDMMutex = NULL;
106
107 /************************************************************************/
108 /*                        GetGDALDriverManager()                        */
109 /*                                                                      */
110 /*      A freestanding function to get the only instance of the         */
111 /*      GDALDriverManager.                                              */
112 /************************************************************************/
113
114 /**
115  * Fetch the global GDAL driver manager.
116  *
117  * This function fetches the pointer to the singleton global driver manager.
118  * If the driver manager doesn't exist it is automatically created.
119  *
120  * @return pointer to the global driver manager.  This should not be able
121  * to fail.
122  */
123
124 GDALDriverManager * GetGDALDriverManager()
125
126 {
127     if( poDM == NULL )
128     {
129         CPLMutexHolderD( &hDMMutex );
130
131         if( poDM == NULL )
132             poDM = new GDALDriverManager();
133     }
134
135     return( (GDALDriverManager *) poDM );
136 }
137
138 /************************************************************************/
139 /*                         GDALDriverManager()                          */
140 /************************************************************************/
141
142 GDALDriverManager::GDALDriverManager()
143
144 {
145     nDrivers = 0;
146     papoDrivers = NULL;
147     pszHome = CPLStrdup("");
148
149     CPLAssert( poDM == NULL );
150
151 /* -------------------------------------------------------------------- */
152 /*      We want to push a location to search for data files             */
153 /*      supporting GDAL/OGR such as EPSG csv files, S-57 definition     */
154 /*      files, and so forth.  The static pszUpdateableINST_DATA         */
155 /*      string can be updated within the shared library or              */
156 /*      executable during an install to point installed data            */
157 /*      directory.  If it isn't burned in here then we use the          */
158 /*      INST_DATA macro (setup at configure time) if                    */
159 /*      available. Otherwise we don't push anything and we hope         */
160 /*      other mechanisms such as environment variables will have        */
161 /*      been employed.                                                  */
162 /* -------------------------------------------------------------------- */
163     if( CPLGetConfigOption( "GDAL_DATA", NULL ) != NULL )
164     {
165         CPLPushFinderLocation( CPLGetConfigOption( "GDAL_DATA", NULL ) );
166     }
167     else if( pszUpdatableINST_DATA[19] != ' ' )
168     {
169         CPLPushFinderLocation( pszUpdatableINST_DATA + 19 );
170     }
171     else
172     {
173 #ifdef INST_DATA
174         CPLPushFinderLocation( INST_DATA );
175 #endif
176     }
177 }
178
179 /************************************************************************/
180 /*                         ~GDALDriverManager()                         */
181 /*                                                                      */
182 /*      Eventually this should also likely clean up all open            */
183 /*      datasets.  Or perhaps the drivers that own them should do       */
184 /*      that in their destructor?                                       */
185 /************************************************************************/
186
187 GDALDriverManager::~GDALDriverManager()
188
189 {
190 /* -------------------------------------------------------------------- */
191 /*      Destroy the existing drivers.                                   */
192 /* -------------------------------------------------------------------- */
193     while( GetDriverCount() > 0 )
194     {
195         GDALDriver      *poDriver = GetDriver(0);
196
197         DeregisterDriver(poDriver);
198         delete poDriver;
199     }
200
201 /* -------------------------------------------------------------------- */
202 /*      Cleanup local memory.                                           */
203 /* -------------------------------------------------------------------- */
204     VSIFree( papoDrivers );
205     VSIFree( pszHome );
206
207 /* -------------------------------------------------------------------- */
208 /*      Blow away all the finder hints paths.  We really shouldn't      */
209 /*      be doing all of them, but it is currently hard to keep track    */
210 /*      of those that actually belong to us.                            */
211 /* -------------------------------------------------------------------- */
212     CPLFinderClean();
213     CPLFreeConfig();
214
215 /* -------------------------------------------------------------------- */
216 /*      Cleanup any memory allocated by the OGRSpatialReference         */
217 /*      related subsystem.                                              */
218 /* -------------------------------------------------------------------- */
219     OSRCleanup();
220
221 /* -------------------------------------------------------------------- */
222 /*      Cleanup VSIFileManager.                                         */
223 /* -------------------------------------------------------------------- */
224     VSICleanupFileManager();
225
226 /* -------------------------------------------------------------------- */
227 /*      Cleanup thread local storage ... I hope the program is all      */
228 /*      done with GDAL/OGR!                                             */
229 /* -------------------------------------------------------------------- */
230     CPLCleanupTLS();
231
232 /* -------------------------------------------------------------------- */
233 /*      Ensure the global driver manager pointer is NULLed out.         */
234 /* -------------------------------------------------------------------- */
235     if( poDM == this )
236         poDM = NULL;
237 }
238
239 /************************************************************************/
240 /*                           GetDriverCount()                           */
241 /************************************************************************/
242
243 /**
244  * Fetch the number of registered drivers.
245  *
246  * This C analog to this is GDALGetDriverCount().
247  *
248  * @return the number of registered drivers.
249  */
250
251 int GDALDriverManager::GetDriverCount()
252
253 {
254     return( nDrivers );
255 }
256
257 /************************************************************************/
258 /*                         GDALGetDriverCount()                         */
259 /************************************************************************/
260
261 /**
262  * @see GDALDriverManager::GetDriverCount()
263  */
264
265 int CPL_STDCALL GDALGetDriverCount()
266
267 {
268     return GetGDALDriverManager()->GetDriverCount();
269 }
270
271 /************************************************************************/
272 /*                             GetDriver()                              */
273 /************************************************************************/
274
275 /**
276  * Fetch driver by index.
277  *
278  * This C analog to this is GDALGetDriver().
279  *
280  * @param iDriver the driver index from 0 to GetDriverCount()-1.
281  *
282  * @return the number of registered drivers.
283  */
284
285 GDALDriver * GDALDriverManager::GetDriver( int iDriver )
286
287 {
288     CPLMutexHolderD( &hDMMutex );
289
290     if( iDriver < 0 || iDriver >= nDrivers )
291         return NULL;
292     else
293         return papoDrivers[iDriver];
294 }
295
296 /************************************************************************/
297 /*                           GDALGetDriver()                            */
298 /************************************************************************/
299
300 /**
301  * @see GDALDriverManager::GetDriver()
302  */
303
304 GDALDriverH CPL_STDCALL GDALGetDriver( int iDriver )
305
306 {
307     return (GDALDriverH) GetGDALDriverManager()->GetDriver(iDriver);
308 }
309
310 /************************************************************************/
311 /*                           RegisterDriver()                           */
312 /************************************************************************/
313
314 /**
315  * Register a driver for use.
316  *
317  * The C analog is GDALRegisterDriver().
318  *
319  * Normally this method is used by format specific C callable registration
320  * entry points such as GDALRegister_GTiff() rather than being called
321  * directly by application level code.
322  *
323  * If this driver (based on the object pointer, not short name) is already
324  * registered, then no change is made, and the index of the existing driver
325  * is returned.  Otherwise the driver list is extended, and the new driver
326  * is added at the end.
327  *
328  * @param poDriver the driver to register.
329  *
330  * @return the index of the new installed driver.
331  */
332
333 int GDALDriverManager::RegisterDriver( GDALDriver * poDriver )
334
335 {
336     CPLMutexHolderD( &hDMMutex );
337
338 /* -------------------------------------------------------------------- */
339 /*      If it is already registered, just return the existing           */
340 /*      index.                                                          */
341 /* -------------------------------------------------------------------- */
342     if( GetDriverByName( poDriver->GetDescription() ) != NULL )
343     {
344         int             i;
345
346         for( i = 0; i < nDrivers; i++ )
347         {
348             if( papoDrivers[i] == poDriver )
349             {
350                 return i;
351             }
352         }
353
354         CPLAssert( FALSE );
355     }
356    
357 /* -------------------------------------------------------------------- */
358 /*      Otherwise grow the list to hold the new entry.                  */
359 /* -------------------------------------------------------------------- */
360     papoDrivers = (GDALDriver **)
361         VSIRealloc(papoDrivers, sizeof(GDALDriver *) * (nDrivers+1));
362
363     papoDrivers[nDrivers] = poDriver;
364     nDrivers++;
365
366     if( poDriver->pfnCreate != NULL )
367         poDriver->SetMetadataItem( GDAL_DCAP_CREATE, "YES" );
368    
369     if( poDriver->pfnCreateCopy != NULL )
370         poDriver->SetMetadataItem( GDAL_DCAP_CREATECOPY, "YES" );
371
372     int iResult = nDrivers - 1;
373
374     return iResult;
375 }
376
377 /************************************************************************/
378 /*                         GDALRegisterDriver()                         */
379 /************************************************************************/
380
381 /**
382  * @see GDALDriverManager::GetRegisterDriver()
383  */
384
385 int CPL_STDCALL GDALRegisterDriver( GDALDriverH hDriver )
386
387 {
388     return GetGDALDriverManager()->RegisterDriver( (GDALDriver *) hDriver );
389 }
390
391
392 /************************************************************************/
393 /*                          DeregisterDriver()                          */
394 /************************************************************************/
395
396 /**
397  * Deregister the passed driver.
398  *
399  * If the driver isn't found no change is made.
400  *
401  * The C analog is GDALDeregisterDriver().
402  *
403  * @param poDriver the driver to deregister.
404  */
405
406 void GDALDriverManager::DeregisterDriver( GDALDriver * poDriver )
407
408 {
409     int         i;
410     CPLMutexHolderD( &hDMMutex );
411
412     for( i = 0; i < nDrivers; i++ )
413     {
414         if( papoDrivers[i] == poDriver )
415             break;
416     }
417
418     if( i == nDrivers )
419         return;
420
421     while( i < nDrivers-1 )
422     {
423         papoDrivers[i] = papoDrivers[i+1];
424         i++;
425     }
426     nDrivers--;
427 }
428
429 /************************************************************************/
430 /*                        GDALDeregisterDriver()                        */
431 /************************************************************************/
432
433 /**
434  * @see GDALDriverManager::GetDeregisterDriver()
435  */
436
437 void CPL_STDCALL GDALDeregisterDriver( GDALDriverH hDriver )
438
439 {
440     GetGDALDriverManager()->DeregisterDriver( (GDALDriver *) hDriver );
441 }
442
443
444 /************************************************************************/
445 /*                          GetDriverByName()                           */
446 /************************************************************************/
447
448 /**
449  * Fetch a driver based on the short name.
450  *
451  * The C analog is the GDALGetDriverByName() function.
452  *
453  * @param pszName the short name, such as GTiff, being searched for.
454  *
455  * @return the identified driver, or NULL if no match is found.
456  */
457
458 GDALDriver * GDALDriverManager::GetDriverByName( const char * pszName )
459
460 {
461     int         i;
462
463     CPLMutexHolderD( &hDMMutex );
464
465     for( i = 0; i < nDrivers; i++ )
466     {
467         if( EQUAL(papoDrivers[i]->GetDescription(), pszName) )
468             return papoDrivers[i];
469     }
470
471     return NULL;
472 }
473
474 /************************************************************************/
475 /*                        GDALGetDriverByName()                         */
476 /************************************************************************/
477
478 /**
479  * @see GDALDriverManager::GetDriverByName()
480  */
481
482 GDALDriverH CPL_STDCALL GDALGetDriverByName( const char * pszName )
483
484 {
485     return( GetGDALDriverManager()->GetDriverByName( pszName ) );
486 }
487
488 /************************************************************************/
489 /*                              GetHome()                               */
490 /************************************************************************/
491
492 const char *GDALDriverManager::GetHome()
493
494 {
495     return pszHome;
496 }
497
498 /************************************************************************/
499 /*                              SetHome()                               */
500 /************************************************************************/
501
502 void GDALDriverManager::SetHome( const char * pszNewHome )
503
504 {
505     CPLMutexHolderD( &hDMMutex );
506
507     CPLFree( pszHome );
508     pszHome = CPLStrdup(pszNewHome);
509 }
510
511 /************************************************************************/
512 /*                          AutoSkipDrivers()                           */
513 /************************************************************************/
514
515 /**
516  * This method unload undesirable drivers.
517  *
518  * All drivers specified in the space delimited list in the GDAL_SKIP
519  * environmentvariable) will be deregistered and destroyed.  This method
520  * should normally be called after registration of standard drivers to allow
521  * the user a way of unloading undesired drivers.  The GDALAllRegister()
522  * function already invokes AutoSkipDrivers() at the end, so if that functions
523  * is called, it should not be necessary to call this method from application
524  * code.
525  */
526
527 void GDALDriverManager::AutoSkipDrivers()
528
529 {
530     if( CPLGetConfigOption( "GDAL_SKIP", NULL ) == NULL )
531         return;
532
533     char **papszList = CSLTokenizeString( CPLGetConfigOption("GDAL_SKIP","") );
534
535     for( int i = 0; i < CSLCount(papszList); i++ )
536     {
537         GDALDriver *poDriver = GetDriverByName( papszList[i] );
538
539         if( poDriver == NULL )
540             CPLError( CE_Warning, CPLE_AppDefined,
541                       "Unable to find driver %s to unload from GDAL_SKIP environment variable.",
542                       papszList[i] );
543         else
544         {
545             CPLDebug( "GDAL", "AutoSkipDriver(%s)", papszList[i] );
546             DeregisterDriver( poDriver );
547             delete poDriver;
548         }
549     }
550
551     CSLDestroy( papszList );
552 }
553
554 /************************************************************************/
555 /*                          AutoLoadDrivers()                           */
556 /************************************************************************/
557
558 /**
559  * Auto-load GDAL drivers from shared libraries.
560  *
561  * This function will automatically load drivers from shared libraries.  It
562  * searches the "driver path" for .so (or .dll) files that start with the
563  * prefix "gdal_X.so".  It then tries to load them and then tries to call
564  * a function within them called GDALRegister_X() where the 'X' is the same
565  * as the remainder of the shared library basename, or failing that to
566  * call GDALRegisterMe(). 
567  *
568  * There are a few rules for the driver path.  If the GDAL_DRIVER_PATH
569  * environment variable it set, it is taken to be a list of directories
570  * to search separated by colons on unix, or semi-colons on Windows.  Otherwise
571  * the /usr/local/lib/gdalplugins directory, and (if known) the lib/gdalplugins
572  * subdirectory of the gdal home directory are searched.
573  */
574
575 void GDALDriverManager::AutoLoadDrivers()
576
577 {
578     char     **papszSearchPath = NULL;
579     const char *pszGDAL_DRIVER_PATH =
580         CPLGetConfigOption( "GDAL_DRIVER_PATH", NULL );
581
582 /* -------------------------------------------------------------------- */
583 /*      Where should we look for stuff?                                 */
584 /* -------------------------------------------------------------------- */
585     if( pszGDAL_DRIVER_PATH != NULL )
586     {
587 #ifdef WIN32
588         papszSearchPath =
589             CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ";", TRUE, FALSE );
590 #else
591         papszSearchPath =
592             CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ":", TRUE, FALSE );
593 #endif
594     }
595     else
596     {
597 #ifdef GDAL_PREFIX
598         papszSearchPath = CSLAddString( papszSearchPath,
599                                         GDAL_PREFIX "/lib/gdalplugins" );
600 #else
601         char szExecPath[1024];
602
603         if( CPLGetExecPath( szExecPath, sizeof(szExecPath) ) )
604         {
605             char szPluginDir[sizeof(szExecPath)+50];
606             strcpy( szPluginDir, CPLGetDirname( szExecPath ) );
607             strcat( szPluginDir, "\\gdalplugins\\" );
608             papszSearchPath = CSLAddString( papszSearchPath, szPluginDir );
609         }
610         else
611         {
612             papszSearchPath = CSLAddString( papszSearchPath,
613                                             "/usr/local/lib/gdalplugins" );
614         }
615 #endif
616
617         if( strlen(GetHome()) > 0 )
618         {
619             papszSearchPath = CSLAddString( papszSearchPath,
620                                   CPLFormFilename( GetHome(),
621                                                    "lib/gdalplugins", NULL ) );
622         }
623     }
624
625 /* -------------------------------------------------------------------- */
626 /*      Scan each directory looking for files starting with gdal_       */
627 /* -------------------------------------------------------------------- */
628     for( int iDir = 0; iDir < CSLCount(papszSearchPath); iDir++ )
629     {
630         char  **papszFiles = CPLReadDir( papszSearchPath[iDir] );
631
632         for( int iFile = 0; iFile < CSLCount(papszFiles); iFile++ )
633         {
634             char   *pszFuncName;
635             const char *pszFilename;
636             const char *pszExtension = CPLGetExtension( papszFiles[iFile] );
637             void   *pRegister;
638
639             if( !EQUALN(papszFiles[iFile],"gdal_",5) )
640                 continue;
641
642             if( !EQUAL(pszExtension,"dll")
643                 && !EQUAL(pszExtension,"so")
644                 && !EQUAL(pszExtension,"dylib") )
645                 continue;
646
647             pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
648             sprintf( pszFuncName, "GDALRegister_%s",
649                      CPLGetBasename(papszFiles[iFile]) + 5 );
650            
651             pszFilename =
652                 CPLFormFilename( papszSearchPath[iDir],
653                                  papszFiles[iFile], NULL );
654
655             pRegister = CPLGetSymbol( pszFilename, pszFuncName );
656             if( pRegister == NULL )
657             {
658                 strcpy( pszFuncName, "GDALRegisterMe" );
659                 pRegister = CPLGetSymbol( pszFilename, pszFuncName );
660             }
661            
662             if( pRegister != NULL )
663             {
664                 CPLDebug( "GDAL", "Auto register %s using %s.",
665                           pszFilename, pszFuncName );
666
667                 ((void (*)()) pRegister)();
668             }
669
670             CPLFree( pszFuncName );
671         }
672
673         CSLDestroy( papszFiles );
674     }
675
676     CSLDestroy( papszSearchPath );
677 }
678
679 /************************************************************************/
680 /*                      GDALDestroyDriverManager()                      */
681 /************************************************************************/
682
683 /**
684  * Destroy the driver manager.
685  *
686  * Incidently unloads all managed drivers.
687  *
688  * NOTE: This function is not thread safe.  It should not be called while
689  * other threads are actively using GDAL.
690  */
691
692 void CPL_STDCALL GDALDestroyDriverManager( void )
693
694 {
695     // THREADSAFETY: We would like to lock the mutex here, but it
696     // needs to be reacquired within the destructor during driver
697     // deregistration.
698     if( poDM != NULL )
699         delete poDM;
700 }
Note: See TracBrowser for help on using the browser.