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