]> Creatis software - cpPlugins.git/blob - lib/cpPlugins/Interface/Plugins.cxx
c114404b1e332602749ebca4f24f045120e0c20c
[cpPlugins.git] / lib / cpPlugins / Interface / Plugins.cxx
1 #include <cpPlugins/Interface/Plugins.h>
2 #include <cpPlugins/OS/DLLManager.h>
3 #include <cpPlugins/Interface/Dirent.h>
4 #include <cpExtensions/Utility.h>
5 #include <regex>
6
7 // -------------------------------------------------------------------------
8 cpPlugins::Interface::Plugins::
9 Pointer cpPlugins::Interface::Plugins::
10 New( )
11 {
12   static Pointer singleton = NULL;
13   if( singleton.IsNull( ) )
14     singleton = new Self( );
15   return( singleton );
16 }
17
18 // -------------------------------------------------------------------------
19 itk::LightObject::Pointer cpPlugins::Interface::Plugins::
20 CreateAnother( ) const
21 {
22   itk::LightObject::Pointer smartPtr;
23   smartPtr = NULL;
24   return( smartPtr );
25 }
26
27 // -------------------------------------------------------------------------
28 cpPlugins::Interface::Plugins::
29 Pointer cpPlugins::Interface::Plugins::
30 Clone( ) const
31 {
32   Pointer r = NULL;
33   return( r );
34 }
35
36 // -------------------------------------------------------------------------
37 cpPlugins::Interface::Plugins::
38 TStrings cpPlugins::Interface::Plugins::
39 GetLibraries( ) const
40 {
41   TStrings res;
42   for(
43     auto i = this->m_Libraries.begin( ); i != this->m_Libraries.end( ); ++i
44     )
45     res.insert( i->first );
46   return( res );
47 }
48
49 // -------------------------------------------------------------------------
50 cpPlugins::Interface::Plugins::
51 TStrings cpPlugins::Interface::Plugins::
52 GetPlugins( ) const
53 {
54   TStrings res;
55   for( auto i = this->m_Plugins.begin( ); i != this->m_Plugins.end( ); ++i )
56     res.insert( i->first );
57   return( res );
58 }
59
60 // -------------------------------------------------------------------------
61 cpPlugins::Interface::Plugins::
62 TStrings cpPlugins::Interface::Plugins::
63 GetCategories( ) const
64 {
65   TStrings res;
66   for( auto i = this->m_Filters.begin( ); i != this->m_Filters.end( ); ++i )
67     res.insert( i->first );
68   return( res );
69 }
70
71 // -------------------------------------------------------------------------
72 cpPlugins::Interface::Plugins::
73 TStrings cpPlugins::Interface::Plugins::
74 GetFilters( const std::string& category ) const
75 {
76   TStrings res;
77   auto cIt = this->m_Filters.find( category );
78   if( cIt != this->m_Filters.end( ) )
79     for( auto i = cIt->second.begin( ); i != cIt->second.end( ); ++i )
80       res.insert( i->first );
81   return( res );
82 }
83
84 // -------------------------------------------------------------------------
85 void cpPlugins::Interface::Plugins::
86 AddEnvironments( const std::string& env )
87 {
88   std::vector< std::string > directories;
89   cpExtensions::Tokenize( directories, env, cpPlugins_ENV_SEPARATOR );
90   for( auto dir = directories.begin( ); dir != directories.end( ); ++dir )
91     this->m_Paths.insert( cpExtensions::CanonicalPath( *dir ) );
92 }
93
94 // -------------------------------------------------------------------------
95 void cpPlugins::Interface::Plugins::
96 LoadEnvironments( )
97 {
98   std::set< std::string > libs;
99   for( auto d = this->m_Paths.begin( ); d != this->m_Paths.end( ); ++d )
100   {
101     std::stringstream fname;
102     fname << *d << cpPlugins_PATH_SEPARATOR << cpPlugins_CONFIG;
103     std::string buffer;
104     if( cpExtensions::Read( buffer, fname.str( ) ) )
105     {
106       std::istringstream input( buffer );
107       for( std::string line; std::getline( input, line ); )
108       {
109         std::vector< std::string > tokens;
110         cpExtensions::Tokenize( tokens, line, "|" );
111         if( tokens.size( ) == 2 )
112         {
113           std::string pth = tokens[ 0 ];
114           std::string lib = tokens[ 1 ];
115           if( lib.find( "*" ) != std::string::npos )
116           {
117             std::string ext( cpPlugins_LIB_EXT );
118             DIR* dir;
119             struct dirent* ent;
120             if( ( dir = opendir( pth.c_str( ) ) ) != NULL )
121             {
122               while( ( ent = readdir( dir ) ) != NULL )
123               {
124                 std::string fname( ent->d_name );
125                 long pos = long( fname.size( ) ) - long( ext.size( ) );
126                 if( pos > 0 )
127                 {
128                   if( fname.substr( pos ) == ext )
129                   {
130                     std::regex re( lib );
131                     std::smatch match;
132                     if( std::regex_search( fname, match, re ) && match.size( ) >= 1 )
133                     {
134                       std::stringstream str;
135                       str
136                         << pth << cpPlugins_PATH_SEPARATOR << fname;
137                       libs.insert( str.str( ) );
138                     } // fi
139
140                   } // fi
141
142                 } // fi
143
144               } // elihw
145               closedir( dir );
146
147             } // fi
148           }
149           else
150           {
151             std::stringstream str;
152             str
153               << pth << cpPlugins_PATH_SEPARATOR << cpPlugins_LIB_PREFIX
154               << lib << cpPlugins_LIB_EXT;
155             libs.insert( str.str( ) );
156
157           } // fi
158
159         } // fi
160
161       } // rof
162
163     } // fi
164
165   } // rof
166   for( auto l = libs.begin( ); l != libs.end( ); ++l )
167   {
168     std::string lib = cpExtensions::CanonicalPath( *l );
169     if( lib != "" )
170     {
171       if( this->m_Libraries.find( lib ) == this->m_Libraries.end( ) )
172       {
173         std::string error = "";
174         void* hnd = cpPlugins::OS::DLLManager::Load( lib, error );
175         if( hnd != NULL )
176           this->m_Libraries[ lib ] = hnd;
177
178       } // fi
179
180     } // fi
181
182   } // rof
183 }
184
185 // -------------------------------------------------------------------------
186 void cpPlugins::Interface::Plugins::
187 LoadPaths( const std::string& dir )
188 {
189   std::stringstream fname, envs;
190   fname << dir;
191   if( !cpExtensions::IsPathSeparator( dir.back( ) ) )
192     fname << cpExtensions_PATH_SEPARATOR;
193   fname << cpPlugins_PATHS;
194   std::string buffer;
195   if( cpExtensions::Read( buffer, fname.str( ) ) )
196   {
197     std::istringstream input( buffer );
198     for( std::string line; std::getline( input, line ); )
199       envs << line << cpPlugins_ENV_SEPARATOR;
200
201   } // fi
202   if( envs.str( ).size( ) > 0 )
203     this->AddEnvironments( envs.str( ) );
204 }
205
206 // -------------------------------------------------------------------------
207 void cpPlugins::Interface::Plugins::
208 SavePaths( const std::string& dir ) const
209 {
210   std::stringstream buffer;
211   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
212     buffer << *i << std::endl;
213
214   std::stringstream fname;
215   fname << dir;
216   if( !cpExtensions::IsPathSeparator( dir.back( ) ) )
217     fname << cpExtensions_PATH_SEPARATOR;
218   fname << cpPlugins_PATHS;
219   if( !cpExtensions::Write( buffer.str( ), fname.str( ) ) )
220     throw std::runtime_error( "Error writing environment file." );
221 }
222
223 // -------------------------------------------------------------------------
224 void cpPlugins::Interface::Plugins::
225 LoadFile( const std::string& fname )
226 {
227   // Resolve canonical filename
228   std::string can_name = cpExtensions::CanonicalPath( fname );
229   if( can_name == "" )
230     throw std::runtime_error(
231       std::string( "Loading file: can't find library \"" ) +
232       fname +
233       std::string( "\"" )
234       );
235   if( this->m_Plugins.find( can_name ) != this->m_Plugins.end( ) )
236     return;
237
238   // Load the library
239   std::string error = "";
240   void* hnd = cpPlugins::OS::DLLManager::Load( can_name, error );
241   if( hnd == NULL )
242     throw std::runtime_error(
243       std::string( "Loading plugin library: " ) + error
244       );
245
246   // Get plugins name
247   typedef const char* ( *_TFunction )( );
248   _TFunction plugins_name_function = ( _TFunction )(
249     cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, "cpPlugins_Name" )
250     );
251   if( plugins_name_function == NULL )
252   {
253     cpPlugins::OS::DLLManager::UnLoad( hnd );
254     throw std::runtime_error(
255       std::string( "Library \"" ) +
256       can_name +
257       std::string( "\" not recognized as a cpPlugins library" )
258       );
259
260   } // fi
261   std::string plugins_name = plugins_name_function( );
262
263   // Get loaded filters
264   _TFunction function = ( _TFunction )(
265     cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, "cpPlugins_LoadedFilters" )
266     );
267   if( function == NULL )
268   {
269     cpPlugins::OS::DLLManager::UnLoad( hnd );
270     throw std::runtime_error(
271       std::string( "Library \"" ) +
272       can_name +
273       std::string( "\" not recognized as a cpPlugins library" )
274       );
275
276   } // fi
277   std::string descriptors = function( );
278   std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
279   std::istringstream str( descriptors );
280   TFilters filters;
281   while( str )
282   {
283     std::string value, category, name;
284     str >> value;
285     if( value == "" )
286       continue;
287     std::replace( value.begin( ), value.end( ), ':', ' ' );
288     std::istringstream value_str( value );
289     value_str >> category >> name;
290
291     // Check if the filter has been already loaded
292     bool found = false;
293     auto fIt = this->m_Filters.find( category );
294     if( fIt != this->m_Filters.end( ) )
295       found = fIt->second.find( name ) != fIt->second.end( );
296     if( found )
297     {
298       cpPlugins::OS::DLLManager::UnLoad( hnd );
299       throw std::runtime_error(
300         std::string( "Filter \"" ) +
301         category + std::string( "::" ) + name +
302         std::string( "\" already exists." )
303         );
304
305     } // fi
306
307     // Get filter creator
308     TCreator creator = ( TCreator )(
309       cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, category + "_" + name )
310       );
311     if( creator == NULL )
312     {
313       cpPlugins::OS::DLLManager::UnLoad( hnd );
314       throw std::runtime_error(
315         std::string( "Filter \"" ) +
316         category + std::string( "::" ) + name +
317         std::string( "\" does not have a valid creator." )
318         );
319
320     } // fi
321
322     TCreatorData data;
323     data.PluginName = plugins_name;
324     data.LibraryHandle = hnd;
325     data.Creator = creator;
326     filters[ category ][ name ] = data;
327
328   } // elihw
329
330   // Keep track of all loaded handlers
331   for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt )
332     for( auto nIt = cIt->second.begin( ); nIt != cIt->second.end( ); ++nIt )
333       this->m_Filters[ cIt->first ][ nIt->first ] = nIt->second;
334   this->m_Plugins[ can_name ] = hnd;
335 }
336
337 // -------------------------------------------------------------------------
338 void cpPlugins::Interface::Plugins::
339 LoadPlugin( const std::string& pname )
340 {
341   std::stringstream fname;
342   fname << cpPlugins_LIB_PREFIX << pname << cpPlugins_LIB_EXT;
343   unsigned int count = 0;
344   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
345   {
346     std::stringstream dir;
347     dir << *i;
348     if( !cpExtensions::IsPathSeparator( i->back( ) ) )
349       dir << cpExtensions_PATH_SEPARATOR;
350     dir << fname.str( );
351     try
352     {
353       this->LoadFile( dir.str( ) );
354     }
355     catch( ... )
356     {
357       count++;
358
359     } // yrt
360
361   } // rof
362
363   // Throw error, if any
364   if( count == this->m_Paths.size( ) )
365     throw std::runtime_error(
366       std::string( "Could not load plugin " ) +
367       std::string( "\"" ) + pname +
368       std::string( "\" from any registered path." )
369       );
370 }
371
372 // -------------------------------------------------------------------------
373 void cpPlugins::Interface::Plugins::
374 LoadDirectory( const std::string& dirname )
375 {
376   DIR* dir;
377   struct dirent* ent;
378   if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
379   {
380     while( ( ent = readdir( dir ) ) != NULL )
381     {
382       try
383       {
384         std::stringstream fname;
385         fname << dirname << cpExtensions_PATH_SEPARATOR << ent->d_name;
386         this->LoadFile( fname.str( ) );
387       }
388       catch( ... ) { }
389
390     } // elihw
391     closedir( dir );
392   }
393   else
394     throw std::runtime_error(
395       std::string( "Could not load directory " ) +
396       std::string( "\"" ) +  dirname + std::string( "\"" )
397       );
398 }
399
400 // -------------------------------------------------------------------------
401 void cpPlugins::Interface::Plugins::
402 GuessPlugins( )
403 {
404   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
405   {
406     try { this->LoadDirectory( *i ); }
407     catch( ... ) { }
408
409   } // rof
410 }
411
412 // -------------------------------------------------------------------------
413 cpPlugins::Interface::Plugins::TProcess::Pointer
414 cpPlugins::Interface::Plugins::
415 CreateProcessObject( const std::string& category, const std::string& name )
416 {
417   typedef cpPlugins::BaseObjects::ProcessObject::Pointer _Ptr;
418   _Ptr o = NULL;
419   auto cIt = this->m_Filters.find( category );
420   if( cIt != this->m_Filters.end( ) )
421   {
422     auto nIt = cIt->second.find( name );
423     if( nIt != cIt->second.end( ) )
424     {
425       o = reinterpret_cast< _Ptr* >( nIt->second.Creator( ) )->GetPointer( );
426       o->SetName( name );
427       o->SetPluginName( nIt->second.PluginName );
428
429     } // fi
430
431   } // fi
432   return( o );
433 }
434
435 // -------------------------------------------------------------------------
436 cpPlugins::Interface::Plugins::
437 Plugins( )
438   : Superclass( )
439 {
440 #ifdef cpPlugins_OS_Windows
441   char* p;
442   size_t size;
443   _dupenv_s( &p, &size, cpPlugins_PATHS );
444 #else // cpPlugins_OS_Windows
445   char* p = std::getenv( cpPlugins_PATHS );
446 #endif // cpPlugins_OS_Windows
447   std::stringstream str;
448   if( p != NULL )
449     str << p << cpPlugins_ENV_SEPARATOR;
450   str << ".";
451   this->AddEnvironments( str.str( ) );
452 }
453
454 // -------------------------------------------------------------------------
455 cpPlugins::Interface::Plugins::
456 ~Plugins( )
457 {
458 }
459
460 // -------------------------------------------------------------------------
461 void cpPlugins::Interface::Plugins::
462 PrintSelf( std::ostream& os, itk::Indent indent ) const
463 {
464   // Show data
465   os << indent << "----- PATHS -----" << std::endl;
466   auto paths = this->GetPaths( );
467   for( auto paIt = paths.begin( ); paIt != paths.end( ); ++paIt )
468     os << indent << *paIt << std::endl;
469   os << indent << std::endl << indent << "----- PLUGINS -----" << std::endl;
470   auto plugins = this->GetPlugins( );
471   for( auto plIt = plugins.begin( ); plIt != plugins.end( ); ++plIt )
472     os << indent << *plIt << std::endl;
473   os << indent << std::endl << indent << "----- FILTERS -----" << std::endl;
474   auto categories = this->GetCategories( );
475   for( auto cIt = categories.begin( ); cIt != categories.end( ); ++cIt )
476   {
477     os << indent << "** Category: " << *cIt << " **" << std::endl;
478     auto filters = this->GetFilters( *cIt );
479     for( auto fIt = filters.begin( ); fIt != filters.end( ); ++fIt )
480       os << indent << indent << indent << "Filter: " << *fIt << std::endl;
481
482   } // rof
483
484 }
485
486 // eof - $RCSfile$