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