]> Creatis software - cpPlugins.git/blob - lib/cpPlugins/Interface.cxx
53b7b118174179807139737986a54f5e9a1ed93b
[cpPlugins.git] / lib / cpPlugins / Interface.cxx
1 #include <cpPlugins/Interface.h>
2
3 #ifdef cpPlugins_SYS_WINDOWS
4 #  include <Windows.h>
5 #else // cpPlugins_SYS_WINDOWS
6 #  include <dlfcn.h>
7 #endif // cpPlugins_SYS_WINDOWS
8 #include <cpPlugins_dirent.h>
9 #include <algorithm>
10
11 // -------------------------------------------------------------------------
12 cpPlugins::Interface::
13 Interface( )
14 {
15 }
16
17 // -------------------------------------------------------------------------
18 cpPlugins::Interface::
19 ~Interface( )
20 {
21   this->UnloadAll( );
22 }
23
24 // -------------------------------------------------------------------------
25 const cpPlugins::Interface::
26 TFilters& cpPlugins::Interface::
27 GetFilters( )
28 {
29   return( this->m_Filters );
30 }
31
32 // -------------------------------------------------------------------------
33 void cpPlugins::Interface::
34 GuessAccesiblePlugins( )
35 {
36   // Load environment configuration
37   char* path = std::getenv( "cpPlugins_PATHS" );
38   if( path != NULL )
39   {
40     std::vector< std::string > tokens;
41     cpPlugins::TokenizeString( tokens, path, "#" );
42     for( auto tIt = tokens.begin( ); tIt != tokens.end( ); ++tIt )
43       try { this->LoadPluginDir( *tIt ); } catch( ... ) { }
44
45   } // fi
46
47   // Load local path
48   auto lpath = cpPlugins::CanonicalPath( "." );
49   try { this->LoadPluginDir( lpath ); } catch( ... ) { }
50 }
51
52 // -------------------------------------------------------------------------
53 bool cpPlugins::Interface::
54 LoadConfiguration( const std::string& filename )
55 {
56   std::ifstream in( filename.c_str( ) );
57   if( !in )
58     return( false );
59
60   this->UnloadAll( );
61   std::string line;
62   while( std::getline( in, line ) )
63     try { this->LoadPluginFile( line ); } catch( ... ) { }
64   return( true );
65 }
66
67 // -------------------------------------------------------------------------
68 bool cpPlugins::Interface::
69 SaveConfiguration( const std::string& filename ) const
70 {
71   std::ofstream out( filename.c_str( ) );
72   if( !out )
73     return( false );
74   auto dIt = this->m_DynLibraries.begin( );
75   for( ; dIt != this->m_DynLibraries.end( ); ++dIt )
76     out << dIt->first << std::endl;
77   out.close( );
78   return( true );
79 }
80
81 // -------------------------------------------------------------------------
82 void cpPlugins::Interface::
83 LoadPluginFile( const std::string& filename )
84 {
85   // Open library with its canonical path name
86   auto canonical_fn = cpPlugins::PathHelper::CanonicalPath( filename );
87   if( canonical_fn == "" )
88     throw std::runtime_error(
89       std::string( "cpPlugins::Interface: Library \"" ) +
90       filename +
91       std::string( "\" does not exist." )
92       );
93
94   // Check if it was already loaded
95   if(
96     this->m_DynLibraries.find( canonical_fn ) != this->m_DynLibraries.end( )
97     )
98     return;
99
100   // Ok, try to load the library
101   void* hnd = Self::_DLOpen( canonical_fn );
102   if( hnd == NULL )
103     throw std::runtime_error(
104       std::string( "cpPlugins::Interface: Could not load library \"" ) +
105       filename +
106       std::string( "\"" )
107       );
108
109   // Load filters
110   TFilters filters = Self::_DLGetFilters( hnd );
111
112   // Save the loaded filters info
113   bool save_handler = false;
114   for( auto catIt = filters.begin( ); catIt != filters.end( ); ++catIt )
115   {
116     // Check if the filter is completely new
117     auto act_catIt = this->m_Filters.find( catIt->first );
118     for(
119       auto clsIt = catIt->second.begin( );
120       clsIt != catIt->second.end( );
121       ++clsIt
122       )
123     {
124       bool new_filter = true;
125       if( act_catIt != this->m_Filters.end( ) )
126         new_filter =
127           ( act_catIt->second.find( *clsIt ) == act_catIt->second.end( ) );
128
129       // Ok, it is new
130       if( new_filter )
131       {
132         // Update filters container
133         auto creator = Self::_DLGetCreator( hnd, catIt->first, *clsIt );
134         if( creator != NULL )
135         {
136           this->m_DynFilters[ catIt->first][ *clsIt ] =
137             TDynFunc( canonical_fn, creator );
138           this->m_Filters[ catIt->first ].insert( *clsIt );
139           save_handler = true;
140
141         } // fi
142
143       } // fi
144
145     } // rof
146
147   } // rof
148
149   // Keep dynlib handler, if needed
150   if( save_handler )
151     this->m_DynLibraries[ canonical_fn ] = hnd;
152   else
153     Self::_DLClose( hnd );
154 }
155
156 // -------------------------------------------------------------------------
157 unsigned int cpPlugins::Interface::
158 LoadPluginDir( const std::string& dirname )
159 {
160   DIR* dir;
161   struct dirent* ent;
162   unsigned int count = 0;
163   if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
164   {
165     while( ( ent = readdir( dir ) ) != NULL )
166     {
167       try
168       {
169         this->LoadPluginFile(
170           dirname +
171           std::string( "/" ) +
172           ent->d_name
173           );
174         count++;
175       }
176       catch( ... ) { }
177
178     } // elihw
179     closedir( dir );
180   }
181   else
182     throw std::runtime_error(
183       std::string( "cpPlugins::Interface: Could not load directory " ) +
184       std::string( "\"" ) +  dirname + std::string( "\"" )
185       );
186   return( count );
187 }
188
189 // -------------------------------------------------------------------------
190 void cpPlugins::Interface::
191 UnloadAll( )
192 {
193   for(
194     auto d = this->m_DynLibraries.begin( );
195     d != this->m_DynLibraries.end( );
196     ++d
197     )
198     Self::_DLClose( d->second );
199   this->m_DynLibraries.clear( );
200   this->m_DynFilters.clear( );
201   this->m_Filters.clear( );
202 }
203
204 // -------------------------------------------------------------------------
205 cpPlugins::ProcessObject::Pointer cpPlugins::Interface::
206 Create( const std::string& category, const std::string& name )
207 {
208   typedef cpPlugins::ProcessObject::Pointer _TPointer;
209   _TPointer filter = NULL;
210   auto catIt = this->m_DynFilters.find( category );
211   if( catIt != this->m_DynFilters.end( ) )
212   {
213     auto clsIt = catIt->second.find( name );
214     if( clsIt != catIt->second.end( ) )
215       filter =
216         ( reinterpret_cast< _TPointer* >( clsIt->second.second( ) ) )->
217         GetPointer( );
218
219   } // fi
220   return( filter );
221 }
222
223 // -------------------------------------------------------------------------
224 void* cpPlugins::Interface::
225 _DLOpen( const std::string& fname )
226 {
227   void* hnd = NULL;
228 #ifdef cpPlugins_SYS_WINDOWS
229   hnd = ::LoadLibraryA( fname.c_str( ) );
230 #else // cpPlugins_SYS_WINDOWS
231   hnd = dlopen( fname.c_str( ), RTLD_NOW | RTLD_GLOBAL );
232   dlerror( );
233 #endif // cpPlugins_SYS_WINDOWS
234   return( hnd );
235 }
236
237 // -------------------------------------------------------------------------
238 cpPlugins::Interface::
239 TFilters cpPlugins::Interface::
240 _DLGetFilters( void* hnd )
241 {
242   // Get descriptors
243   typedef const char* ( *f_t )( );
244   f_t f = NULL;
245 #ifdef cpPlugins_SYS_WINDOWS
246   f = ( f_t )( ::GetProcAddress( ( HMODULE )hnd, "cpPlugins_LoadedFilters" ) );
247 #else // cpPlugins_SYS_WINDOWS
248   f = ( f_t )( dlsym( hnd, "cpPlugins_LoadedFilters" ) );
249 #endif // cpPlugins_SYS_WINDOWS
250   if( f == NULL )
251   {
252     Self::_DLClose( hnd );
253     throw std::runtime_error(
254       "cpPlugins::Interface: Library not recognized as a cpPlugins library: "
255       );
256
257   } // fi
258   std::string descriptors = f( );
259
260   // Demangle descriptors
261   TFilters filters;
262   std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
263   std::istringstream str( descriptors );
264   while( str )
265   {
266     std::string value, category, name;
267     str >> value;
268     if( value == "" )
269       continue;
270     std::replace( value.begin( ), value.end( ), ':', ' ' );
271     std::istringstream value_str( value );
272     value_str >> category >> name;
273     filters[ category ].insert( name );
274
275   } // elihw
276   return( filters );
277 }
278
279 // -------------------------------------------------------------------------
280 cpPlugins::Interface::
281 TCreator cpPlugins::Interface::
282 _DLGetCreator(
283   void* hnd, const std::string& category, const std::string& name
284   )
285 {
286   TCreator c = NULL;
287   std::string func_name = category + "_" + name;
288 #ifdef cpPlugins_SYS_WINDOWS
289   c = ( TCreator )( ::GetProcAddress( ( HMODULE )hnd, func_name.c_str( ) ) );
290 #else // cpPlugins_SYS_WINDOWS
291   c = ( TCreator )( dlsym( hnd, func_name.c_str( ) ) );
292 #endif // cpPlugins_SYS_WINDOWS
293   if( c == NULL )
294     throw std::runtime_error(
295       std::string( "cpPlugins::Interface: Class \"" ) +
296       category + std::string( ":" ) + name +
297       std::string( "\" does not have a valid creator function." )
298       );
299   return( c );
300 }
301
302 // -------------------------------------------------------------------------
303 void cpPlugins::Interface::
304 _DLClose( void* hnd )
305 {
306 #ifdef cpPlugins_SYS_WINDOWS
307   ::FreeLibrary( ( HMODULE )hnd );
308 #else // cpPlugins_SYS_WINDOWS
309   dlclose( hnd );
310 #endif // cpPlugins_SYS_WINDOWS
311 }
312
313 // eof - $RCSfile$