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