]> Creatis software - cpPlugins.git/blobdiff - lib/cpPlugins/Interface.cxx
...
[cpPlugins.git] / lib / cpPlugins / Interface.cxx
index de6d63116e6c0b2b35bf58c1c4f9d0ba2bf72de5..58e468d29e114cc2b802a22fab6cb1b8f90d07f2 100644 (file)
@@ -1,14 +1,11 @@
 #include <cpPlugins/Interface.h>
 
-#include <map>
-#include <set>
-#include <string>
-
 #ifdef cpPlugins_SYS_WINDOWS
+#  include <Windows.h>
 #else // cpPlugins_SYS_WINDOWS
 #  include <dlfcn.h>
 #endif // cpPlugins_SYS_WINDOWS
-
+#include <cpPlugins_dirent.h>
 
 // -------------------------------------------------------------------------
 cpPlugins::Interface::
@@ -31,88 +28,162 @@ GetFilters( )
   return( this->m_Filters );
 }
 
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::
+LoadConfiguration( const std::string& filename )
+{
+  std::ifstream in( filename.c_str( ) );
+  if( !in )
+    return( false );
+
+  this->UnloadAll( );
+  std::string line;
+  while( std::getline( in, line ) )
+  {
+    try
+    {
+      this->LoadPluginFile( line );
+    }
+    catch( ... )
+    {
+      // Do nothing
+
+    } // yrt
+
+  } // elihw
+  return( true );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::
+SaveConfiguration( const std::string& filename ) const
+{
+  std::ofstream out( filename.c_str( ) );
+  if( !out )
+    return( false );
+  auto dIt = this->m_DynLibraries.begin( );
+  for( ; dIt != this->m_DynLibraries.end( ); ++dIt )
+    out << dIt->first << std::endl;
+  out.close( );
+  return( true );
+}
+
 // -------------------------------------------------------------------------
 void cpPlugins::Interface::
 LoadPluginFile( const std::string& filename )
 {
+  // Open library with its canonical path name
   auto canonical_fn = cpPlugins::PathHelper::CanonicalPath( filename );
-  void* hnd = NULL;
-  std::map< std::string, std::set< std::string > > filters;
-#ifdef cpPlugins_SYS_WINDOWS
-  // TODO:
-#else // cpPlugins_SYS_WINDOWS
+  if( canonical_fn == "" )
+    throw std::runtime_error(
+      std::string( "cpPlugins::Interface: Library \"" ) +
+      filename +
+      std::string( "\" does not exist." )
+      );
+
+  // Check if it was already loaded
+  if( this->m_DynLibraries.find( canonical_fn ) != this->m_DynLibraries.end( ) )
+    return;
 
-  // Try to load canonical filename and clean error messages
-  hnd = dlopen( canonical_fn.c_str( ), RTLD_NOW | RTLD_GLOBAL );
+  // Ok, try to load the library
+  void* hnd = Self::_DLOpen( canonical_fn );
   if( hnd == NULL )
     throw std::runtime_error(
       std::string( "cpPlugins::Interface: Could not load library \"" ) +
-      canonical_fn +
+      filename +
       std::string( "\"" )
       );
-  dlerror( );
 
-  // Init plugins
-  typedef const std::map< std::string, std::set< std::string > > ( *func_t )( );
-  auto func = ( func_t ) dlsym( hnd, "LoadedFilters" );
-  const char* func_error = dlerror( );
-  if( func_error != NULL )
-  {
-    dlclose( hnd );
-    throw std::runtime_error(
-      std::string( "cpPlugins::Interface: Library \"" ) +
-      canonical_fn +
-      std::string( "\" not recognized as a cpPlugins library." )
-      );
+  // Load filters
+  TFilters filters = Self::_DLGetFilters( hnd );
 
-  } // fi
-  filters = func( );
-#endif // cpPlugins_SYS_WINDOWS
-  if( hnd != NULL )
+  // Save the loaded filters info
+  bool save_handler = false;
+  for( auto catIt = filters.begin( ); catIt != filters.end( ); ++catIt )
   {
-    // Save the loaded filters names
-    for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt )
+    // Check if the filter is completely new
+    auto act_catIt = this->m_Filters.find( catIt->first );
+    for(
+      auto clsIt = catIt->second.begin( );
+      clsIt != catIt->second.end( );
+      ++clsIt
+      )
     {
-      auto colIt = this->m_Filters.find( cIt->first );
-      for( auto fIt = cIt->second.begin( ); fIt != cIt->second.end( ); ++fIt )
+      bool new_filter = true;
+      if( act_catIt != this->m_Filters.end( ) )
+        new_filter =
+          ( act_catIt->second.find( *clsIt ) == act_catIt->second.end( ) );
+
+      // Ok, it is new
+      if( new_filter )
       {
-        bool found = false;
-        if( colIt != this->m_Filters.end( ) )
+        // Update filters container
+        auto creator = Self::_DLGetCreator( hnd, catIt->first, *clsIt );
+        if( creator != NULL )
         {
-          auto rowIt = colIt->second.find( *fIt );
-          if( rowIt != colIt->second.end( ) )
-            found = true;
+          this->m_DynFilters[ catIt->first][ *clsIt ] =
+            TDynFunc( canonical_fn, creator );
+          this->m_Filters[ catIt->first ].insert( *clsIt );
+          save_handler = true;
 
         } // fi
-        if( !found )
-          this->m_Filters[ cIt->first ][ *fIt ] = canonical_fn;
 
-      } // rof
+      } // fi
 
     } // rof
 
-    // Save the hnd
-    this->m_Plugins[ canonical_fn ] = hnd;
+  } // rof
+
+  // Keep dynlib handler, if needed
+  if( save_handler )
+    this->m_DynLibraries[ canonical_fn ] = hnd;
+  else
+    Self::_DLClose( hnd );
+}
+
+// -------------------------------------------------------------------------
+unsigned int cpPlugins::Interface::
+LoadPluginDir( const std::string& dirname )
+{
+  DIR* dir;
+  struct dirent* ent;
+  unsigned int count = 0;
+  if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
+  {
+    while( ( ent = readdir( dir ) ) != NULL )
+    {
+      try
+      {
+        this->LoadPluginFile( ent->d_name );
+        count++;
+      }
+      catch( ... )
+      {
+        // Ignore errors
+      } // yrt
+    } // elihw
+    closedir( dir );
   }
   else
     throw std::runtime_error(
-      "cpPlugins::Interface: Operative system not yet supported."
+      std::string( "cpPlugins::Interface: Could not load directory " ) +
+      std::string( "\"" ) +  dirname + std::string( "\"" )
       );
+  return( count );
 }
 
 // -------------------------------------------------------------------------
 void cpPlugins::Interface::
 UnloadAll( )
 {
-  auto pIt = this->m_Plugins.begin( );
-  for( ; pIt != this->m_Plugins.end( ); ++pIt )
-  {
-#ifdef cpPlugins_SYS_WINDOWS
-#else // cpPlugins_SYS_WINDOWS
-    dlclose( pIt->second );
-#endif // cpPlugins_SYS_WINDOWS
-  } // rof
-  this->m_Plugins.clear( );
+  for(
+    auto d = this->m_DynLibraries.begin( );
+    d != this->m_DynLibraries.end( );
+    ++d
+    )
+    Self::_DLClose( d->second );
+  this->m_DynLibraries.clear( );
+  this->m_DynFilters.clear( );
   this->m_Filters.clear( );
 }
 
@@ -120,38 +191,109 @@ UnloadAll( )
 cpPlugins::ProcessObject::Pointer cpPlugins::Interface::
 Create( const std::string& category, const std::string& name )
 {
-  cpPlugins::ProcessObject::Pointer filter;
-  auto cIt = this->m_Filters.find( category );
-  if( cIt != this->m_Filters.end( ) )
+  typedef cpPlugins::ProcessObject::Pointer _TPointer;
+  _TPointer filter = NULL;
+  auto catIt = this->m_DynFilters.find( category );
+  if( catIt != this->m_DynFilters.end( ) )
   {
-    auto nIt = cIt->second.find( name );
-    if( nIt != cIt->second.end( ) )
-    {
-      auto pIt = this->m_Plugins.find( nIt->second );
-      if( pIt != this->m_Plugins.end( ) )
-      {
+    auto clsIt = catIt->second.find( name );
+    if( clsIt != catIt->second.end( ) )
+      filter =
+        ( reinterpret_cast< _TPointer* >( clsIt->second.second( ) ) )->
+        GetPointer( );
+
+  } // fi
+  return( filter );
+}
+
+// -------------------------------------------------------------------------
+void* cpPlugins::Interface::
+_DLOpen( const std::string& fname )
+{
+  void* hnd = NULL;
 #ifdef cpPlugins_SYS_WINDOWS
+  hnd = ::LoadLibraryA( fname.c_str( ) );
 #else // cpPlugins_SYS_WINDOWS
-        std::string func_name = category + "_" + name;
-        typedef cpPlugins::ProcessObject::Pointer ( *func_t )( );
-        auto func = ( func_t ) dlsym( pIt->second, func_name.c_str( ) );
-        if( func == NULL )
-        {
-          throw std::runtime_error(
-            std::string( "cpPlugins::Interface: Class \"" ) +
-            category + std::string( ":" ) + name +
-            std::string( "\" does not have a valid creator function." )
-            );
-
-        } // fi
-        filter = func( );
+  hnd = dlopen( fname.c_str( ), RTLD_NOW | RTLD_GLOBAL );
+  dlerror( );
 #endif // cpPlugins_SYS_WINDOWS
-      } // fi
+  return( hnd );
+}
 
-    } // fi
+// -------------------------------------------------------------------------
+cpPlugins::Interface::
+TFilters cpPlugins::Interface::
+_DLGetFilters( void* hnd )
+{
+  // Get descriptors
+  typedef const char* ( *f_t )( );
+  f_t f = NULL;
+#ifdef cpPlugins_SYS_WINDOWS
+  f = ( f_t )( ::GetProcAddress( ( HMODULE )hnd, "cpPlugins_LoadedFilters" ) );
+#else // cpPlugins_SYS_WINDOWS
+  f = ( f_t )( dlsym( hnd, "cpPlugins_LoadedFilters" ) );
+#endif // cpPlugins_SYS_WINDOWS
+  if( f == NULL )
+  {
+    Self::_DLClose( hnd );
+    throw std::runtime_error(
+      "cpPlugins::Interface: Library not recognized as a cpPlugins library: "
+      );
 
   } // fi
-  return( filter );
+  std::string descriptors = f( );
+
+  // Demangle descriptors
+  TFilters filters;
+  std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
+  std::istringstream str( descriptors );
+  while( str )
+  {
+    std::string value, category, name;
+    str >> value;
+    if( value == "" )
+      continue;
+    std::replace( value.begin( ), value.end( ), ':', ' ' );
+    std::istringstream value_str( value );
+    value_str >> category >> name;
+    filters[ category ].insert( name );
+
+  } // elihw
+  return( filters );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Interface::
+TCreator cpPlugins::Interface::
+_DLGetCreator(
+  void* hnd, const std::string& category, const std::string& name
+  )
+{
+  TCreator c = NULL;
+  std::string func_name = category + "_" + name;
+#ifdef cpPlugins_SYS_WINDOWS
+  c = ( TCreator )( ::GetProcAddress( ( HMODULE )hnd, func_name.c_str( ) ) );
+#else // cpPlugins_SYS_WINDOWS
+  c = ( TCreator )( dlsym( hnd, func_name.c_str( ) ) );
+#endif // cpPlugins_SYS_WINDOWS
+  if( c == NULL )
+    throw std::runtime_error(
+      std::string( "cpPlugins::Interface: Class \"" ) +
+      category + std::string( ":" ) + name +
+      std::string( "\" does not have a valid creator function." )
+      );
+  return( c );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Interface::
+_DLClose( void* hnd )
+{
+#ifdef cpPlugins_SYS_WINDOWS
+  ::FreeLibrary( ( HMODULE )hnd );
+#else // cpPlugins_SYS_WINDOWS
+  dlclose( hnd );
+#endif // cpPlugins_SYS_WINDOWS
 }
 
 // eof - $RCSfile$