]> Creatis software - cpPlugins.git/blob - lib/cpPlugins/Interface.cxx
1f78e27976998f1dd6f53c3f48c1f59a3b7cb53b
[cpPlugins.git] / lib / cpPlugins / Interface.cxx
1 #include <cpPlugins/Interface.h>
2 #include <cpPlugins/Utilities.h>
3 #include <cpPlugins/DLLManager.h>
4 #include <cpPlugins/dirent.h>
5 #include <algorithm>
6
7 // -------------------------------------------------------------------------
8 cpPlugins::Interface::
9 Interface( )
10 {
11   char* p = std::getenv( cpPlugins_PATHS );
12   std::stringstream str;
13   if( p != NULL )
14     str << p << cpPlugins_SEPARATOR;
15   str << ".";
16   this->AddEnvironments( str.str( ) );
17 }
18
19 // -------------------------------------------------------------------------
20 cpPlugins::Interface::
21 ~Interface( )
22 {
23 }
24
25 // -------------------------------------------------------------------------
26 const cpPlugins::Interface::
27 TStrings& cpPlugins::Interface::
28 GetPaths( ) const
29 {
30   return( this->m_Paths );
31 }
32
33 // -------------------------------------------------------------------------
34 cpPlugins::Interface::
35 TStrings cpPlugins::Interface::
36 GetLibraries( ) const
37 {
38   TStrings res;
39   for(
40     auto i = this->m_Libraries.begin( ); i != this->m_Libraries.end( ); ++i
41     )
42     res.insert( i->first );
43   return( res );
44 }
45
46 // -------------------------------------------------------------------------
47 cpPlugins::Interface::
48 TStrings cpPlugins::Interface::
49 GetPlugins( ) const
50 {
51   TStrings res;
52   for( auto i = this->m_Plugins.begin( ); i != this->m_Plugins.end( ); ++i )
53     res.insert( i->first );
54   return( res );
55 }
56
57 // -------------------------------------------------------------------------
58 cpPlugins::Interface::
59 TStrings cpPlugins::Interface::
60 GetCategories( ) const
61 {
62   TStrings res;
63   for( auto i = this->m_Filters.begin( ); i != this->m_Filters.end( ); ++i )
64     res.insert( i->first );
65   return( res );
66 }
67
68 // -------------------------------------------------------------------------
69 cpPlugins::Interface::
70 TStrings cpPlugins::Interface::
71 GetFilters( const std::string& category ) const
72 {
73   TStrings res;
74   auto cIt = this->m_Filters.find( category );
75   if( cIt != this->m_Filters.end( ) )
76     for( auto i = cIt->second.begin( ); i != cIt->second.end( ); ++i )
77       res.insert( i->first );
78   return( res );
79 }
80
81 // -------------------------------------------------------------------------
82 void cpPlugins::Interface::
83 AddEnvironments( const std::string& new_environment )
84 {
85   std::vector< std::string > tokens;
86   cpPlugins::TokenizeString( tokens, new_environment, cpPlugins_SEPARATOR );
87   for( auto i = tokens.begin( ); i != tokens.end( ); ++i )
88   {
89     std::stringstream dir;
90     dir << cpPlugins::CanonicalPath( *i );
91     if( dir.str( ) != "" )
92     {
93       if( !cpPlugins::IsPathSeparator( dir.str( ).back( ) ) )
94         dir << cpPlugins_PATH_SEPARATOR;
95       std::stringstream name;
96       name << dir.str( ) << cpPlugins_CONFIG;
97       std::ifstream check( name.str( ).c_str( ), std::ifstream::binary );
98       if( check )
99         this->m_Paths.insert( dir.str( ) );
100       check.close( );
101
102     } // fi
103
104   } // rof
105 }
106
107 // -------------------------------------------------------------------------
108 void cpPlugins::Interface::
109 LoadEnvironments( )
110 {
111   std::stringstream all_errors;
112   for( auto d = this->m_Paths.begin( ); d != this->m_Paths.end( ); ++d )
113   {
114     std::stringstream name;
115     name << *d << cpPlugins_CONFIG;
116     std::string buffer;
117     if( cpPlugins::ReadFileIntoBuffer( buffer, name.str( ) ) )
118     {
119       std::istringstream input( buffer );
120       for( std::string line; std::getline( input, line ); )
121       {
122         std::vector< std::string > tokens;
123         cpPlugins::TokenizeString( tokens, line, "@" );
124         std::string library_file = "";
125         if( tokens[ 0 ] == "local" )
126           library_file =
127             cpPlugins::CanonicalPath(
128               *d + std::string( cpPlugins_LIB_PREFIX ) +
129               tokens[ 1 ] + std::string( "." ) + 
130               std::string( cpPlugins_LIB_EXT )
131               );
132         else if( tokens[ 0 ] == "global" )
133           library_file = tokens[ 1 ];
134
135         if( library_file != "" )
136         {
137           std::string error = "";
138           void* hnd = cpPlugins::DLLManager::Load( library_file, error );
139           if( hnd != NULL )
140             this->m_Libraries[ library_file ] = hnd;
141           else
142             all_errors << " ; " << error;
143
144         } // fi
145
146       } // rof
147
148     } // fi
149
150   } // rof
151
152   // Throw errors
153   if( all_errors.str( ) != "" )
154     throw std::runtime_error(
155       std::string( "Loading environment libraries errors: " ) +
156       all_errors.str( )
157       );
158 }
159
160 // -------------------------------------------------------------------------
161 void cpPlugins::Interface::
162 SaveEnvironments( const std::string& dir ) const
163 {
164   if( this->m_Paths.size( ) > 0 )
165   {
166     std::stringstream buffer;
167     auto i = this->m_Paths.begin( );
168     for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
169       buffer << *i << std::endl;
170
171     std::stringstream fname;
172     fname << dir;
173     if( !cpPlugins::IsPathSeparator( dir.back( ) ) )
174       fname << cpPlugins_PATH_SEPARATOR;
175     fname << cpPlugins_PATHS;
176     if( !cpPlugins::WriteBufferToFile( buffer.str( ), fname.str( ) ) )
177       throw std::runtime_error( "Error writing environment file." );
178   }
179   else
180     throw std::runtime_error( "No paths to save." );
181 }
182
183 // -------------------------------------------------------------------------
184 void cpPlugins::Interface::
185 OpenEnvironments( const std::string& dir )
186 {
187   std::stringstream fname;
188   fname << dir;
189   if( !cpPlugins::IsPathSeparator( dir.back( ) ) )
190     fname << cpPlugins_PATH_SEPARATOR;
191   fname << cpPlugins_PATHS;
192   std::string buffer;
193   if( cpPlugins::ReadFileIntoBuffer( buffer, fname.str( ) ) )
194   {
195     std::istringstream input( buffer );
196     std::stringstream paths;
197     for( std::string line; std::getline( input, line ); )
198       paths << line << cpPlugins_SEPARATOR;
199     this->AddEnvironments( paths.str( ) );
200   }
201   else
202     throw std::runtime_error( "Error opening environment file." );
203 }
204
205 // -------------------------------------------------------------------------
206 void cpPlugins::Interface::
207 LoadFile( const std::string& fname )
208 {
209   // Resolve canonical filename
210   std::string can_name = cpPlugins::CanonicalPath( fname );
211   if( can_name == "" )
212     throw std::runtime_error(
213       std::string( "Loading file: can't find library \"" ) +
214       fname +
215       std::string( "\"" )
216       );
217   if( this->m_Plugins.find( can_name ) != this->m_Plugins.end( ) )
218     return;
219
220   // Load the library
221   std::string error = "";
222   void* hnd = cpPlugins::DLLManager::Load( can_name, error );
223   if( hnd == NULL )
224     throw std::runtime_error(
225       std::string( "Loading plugin library: " ) + error
226       );
227
228   // Get plugins name
229   typedef const char* ( *_TFunction )( );
230   _TFunction plugins_name_function = ( _TFunction )(
231     cpPlugins::DLLManager::GetFunctionHandle( hnd, "cpPlugins_Name" )
232     );
233   if( plugins_name_function == NULL )
234   {
235     cpPlugins::DLLManager::UnLoad( hnd );
236     throw std::runtime_error(
237       std::string( "Library \"" ) +
238       can_name +
239       std::string( "\" not recognized as a cpPlugins library" )
240       );
241
242   } // fi
243   std::string plugins_name = plugins_name_function( );
244
245   // Get loaded filters
246   _TFunction function = ( _TFunction )(
247     cpPlugins::DLLManager::GetFunctionHandle( hnd, "cpPlugins_LoadedFilters" )
248     );
249   if( function == NULL )
250   {
251     cpPlugins::DLLManager::UnLoad( hnd );
252     throw std::runtime_error(
253       std::string( "Library \"" ) +
254       can_name +
255       std::string( "\" not recognized as a cpPlugins library" )
256       );
257
258   } // fi
259   std::string descriptors = function( );
260   std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
261   std::istringstream str( descriptors );
262   TFilters filters;
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
273     // Check if the filter has been already loaded
274     bool found = false;
275     auto fIt = this->m_Filters.find( category );
276     if( fIt != this->m_Filters.end( ) )
277       found = fIt->second.find( name ) != fIt->second.end( );
278     if( found )
279     {
280       cpPlugins::DLLManager::UnLoad( hnd );
281       throw std::runtime_error(
282         std::string( "Filter \"" ) +
283         category + std::string( "::" ) + name +
284         std::string( "\" already exists." )
285         );
286
287     } // fi
288
289     // Get filter creator
290     TCreator creator = ( TCreator )(
291       cpPlugins::DLLManager::GetFunctionHandle( hnd, category + "_" + name )
292       );
293     if( creator == NULL )
294     {
295       cpPlugins::DLLManager::UnLoad( hnd );
296       throw std::runtime_error(
297         std::string( "Filter \"" ) +
298         category + std::string( "::" ) + name +
299         std::string( "\" does not have a valid creator." )
300         );
301
302     } // fi
303
304     TCreatorData data;
305     data.PluginName = plugins_name;
306     data.LibraryHandle = hnd;
307     data.Creator = creator;
308     filters[ category ][ name ] = data;
309
310   } // elihw
311
312   // Keep track of all loaded handlers
313   for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt )
314     for( auto nIt = cIt->second.begin( ); nIt != cIt->second.end( ); ++nIt )
315       this->m_Filters[ cIt->first ][ nIt->first ] = nIt->second;
316   this->m_Plugins[ can_name ] = hnd;
317 }
318
319 // -------------------------------------------------------------------------
320 void cpPlugins::Interface::
321 LoadPlugin( const std::string& pname )
322 {
323   std::stringstream fname;
324   fname << cpPlugins_LIB_PREFIX << pname << "." << cpPlugins_LIB_EXT;
325   unsigned int count = 0;
326   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
327   {
328     std::stringstream dir;
329     dir << *i;
330     if( !cpPlugins::IsPathSeparator( i->back( ) ) )
331       dir << cpPlugins_PATH_SEPARATOR;
332     dir << fname.str( );
333     try
334     {
335       this->LoadFile( dir.str( ) );
336     }
337     catch( ... )
338     {
339       count++;
340
341     } // yrt
342
343   } // rof
344
345   // Throw error, if any
346   if( count == this->m_Paths.size( ) )
347     throw std::runtime_error(
348       std::string( "Could not load plugin " ) +
349       std::string( "\"" ) + pname +
350       std::string( "\" from any registered path." )
351       );
352 }
353
354 // -------------------------------------------------------------------------
355 void cpPlugins::Interface::
356 LoadDirectory( const std::string& dirname )
357 {
358   DIR* dir;
359   struct dirent* ent;
360   if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
361   {
362     while( ( ent = readdir( dir ) ) != NULL )
363     {
364       try
365       {
366         std::stringstream fname;
367         fname << dirname << cpPlugins_PATH_SEPARATOR << ent->d_name;
368         this->LoadFile( fname.str( ) );
369       }
370       catch( ... ) { }
371
372     } // elihw
373     closedir( dir );
374   }
375   else
376     throw std::runtime_error(
377       std::string( "Could not load directory " ) +
378       std::string( "\"" ) +  dirname + std::string( "\"" )
379       );
380 }
381
382 // -------------------------------------------------------------------------
383 void cpPlugins::Interface::
384 GuessPlugins( )
385 {
386   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
387   {
388     try { this->LoadDirectory( *i ); }
389     catch( ... ) { }
390
391   } // rof
392 }
393
394 // -------------------------------------------------------------------------
395 cpPlugins::ProcessObject::Pointer cpPlugins::Interface::
396 CreateProcessObject( const std::string& category, const std::string& name )
397 {
398   typedef cpPlugins::ProcessObject::Pointer _Ptr;
399   _Ptr o = NULL;
400   auto cIt = this->m_Filters.find( category );
401   if( cIt != this->m_Filters.end( ) )
402   {
403     auto nIt = cIt->second.find( name );
404     if( nIt != cIt->second.end( ) )
405     {
406       o = reinterpret_cast< _Ptr* >( nIt->second.Creator( ) )->GetPointer( );
407       o->SetName( name );
408       o->SetPluginName( nIt->second.PluginName );
409
410     } // fi
411
412   } // fi
413   return( o );
414 }
415
416 // eof - $RCSfile$