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