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