#include #ifdef cpPlugins_SYS_WINDOWS # include #else // cpPlugins_SYS_WINDOWS # include #endif // cpPlugins_SYS_WINDOWS #include #include // ------------------------------------------------------------------------- cpPlugins::Interface:: Interface( ) { this->UpdatePaths( ); } // ------------------------------------------------------------------------- cpPlugins::Interface:: ~Interface( ) { this->UnloadAll( ); } // ------------------------------------------------------------------------- const cpPlugins::Interface:: TFilters& cpPlugins::Interface:: GetFilters( ) { return( this->m_Filters ); } // ------------------------------------------------------------------------- void cpPlugins::Interface:: UpdatePaths( ) { // Load environment configuration this->m_Paths.clear( ); char* p = std::getenv( cpPlugins_PATHS ); if( p != NULL ) cpPlugins::TokenizeString( this->m_Paths, p, cpPlugins_SEPARATOR ); this->m_Paths.push_back( "." ); } // ------------------------------------------------------------------------- void cpPlugins::Interface:: GuessAccesiblePlugins( ) { for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i ) try { this->LoadPluginDir( *i ); } catch( ... ) { } } // ------------------------------------------------------------------------- void cpPlugins::Interface:: LoadPlugin( const std::string& name ) { std::stringstream str; str << cpPlugins_LIB_PREFIX << name << "." << cpPlugins_LIB_EXT; std::string base_name = str.str( ); bool found = false; for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i ) { std::string filename = *i; if( i->back( ) != '/' ) filename += std::string( "/" ); filename += base_name; try { this->LoadPluginFile( filename ); found = true; } catch( ... ) { } // yrt } // rof if( !found ) throw std::runtime_error( std::string( "cpPlugins::Interface: Plugins library \"" ) + name + std::string( "\" not found." ) ); } // ------------------------------------------------------------------------- void cpPlugins::Interface:: LoadPluginDir( const std::string& dirname ) { DIR* dir; struct dirent* ent; if( ( dir = opendir( dirname.c_str( ) ) ) != NULL ) { while( ( ent = readdir( dir ) ) != NULL ) { try { this->LoadPluginFile( dirname + std::string( "/" ) + ent->d_name ); } catch( ... ) { } } // elihw closedir( dir ); } else throw std::runtime_error( std::string( "cpPlugins::Interface: Could not load directory " ) + std::string( "\"" ) + dirname + std::string( "\"" ) ); } // ------------------------------------------------------------------------- void cpPlugins::Interface:: LoadPluginFile( const std::string& filename ) { // Canonical filename auto canonical = cpPlugins::CanonicalPath( filename ); if( canonical == "" ) throw std::runtime_error( std::string( "cpPlugins::Interface: Library \"" ) + filename + std::string( "\" does not exist." ) ); // Try to load the library void* hnd = Self::_DLOpen( canonical ); if( hnd == NULL ) throw std::runtime_error( std::string( "cpPlugins::Interface: Could not load library \"" ) + filename + std::string( "\"" ) ); // Get plugin name std::string pl_name = Self::_DLGetName( hnd ); // Check if it was already loaded if( this->m_DynLibraries.find( pl_name ) != this->m_DynLibraries.end( ) ) return; // Load filters TFilters filters = Self::_DLGetFilters( hnd ); // Save the loaded filters info bool save_handler = false; for( auto catIt = filters.begin( ); catIt != filters.end( ); ++catIt ) { // 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 ) { 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 ) { // Update filters container auto creator = Self::_DLGetCreator( hnd, catIt->first, *clsIt ); if( creator != NULL ) { this->m_DynFilters[ catIt->first][ *clsIt ] = TDynFunc( pl_name, creator ); this->m_Filters[ catIt->first ].insert( *clsIt ); save_handler = true; } // fi } // fi } // rof } // rof // Keep dynlib handler, if needed if( save_handler ) this->m_DynLibraries[ pl_name ] = TDynFileInfo( canonical, hnd ); else Self::_DLClose( hnd ); } // ------------------------------------------------------------------------- void cpPlugins::Interface:: UnloadAll( ) { for( auto d = this->m_DynLibraries.begin( ); d != this->m_DynLibraries.end( ); ++d ) Self::_DLClose( d->second.second ); this->m_DynLibraries.clear( ); this->m_DynFilters.clear( ); this->m_Filters.clear( ); } // ------------------------------------------------------------------------- cpPlugins::ProcessObject::Pointer cpPlugins::Interface:: Create( const std::string& category, const std::string& name ) { typedef cpPlugins::ProcessObject::Pointer _TPointer; _TPointer filter = NULL; auto catIt = this->m_DynFilters.find( category ); if( catIt != this->m_DynFilters.end( ) ) { auto clsIt = catIt->second.find( name ); if( clsIt != catIt->second.end( ) ) filter = ( reinterpret_cast< _TPointer* >( clsIt->second.second( ) ) )-> GetPointer( ); } // fi return( filter ); } // ------------------------------------------------------------------------- std::string cpPlugins::Interface:: GetPluginName( const std::string& category, const std::string& name ) const { std::string plugin = ""; auto catIt = this->m_DynFilters.find( category ); if( catIt != this->m_DynFilters.end( ) ) { auto clsIt = catIt->second.find( name ); if( clsIt != catIt->second.end( ) ) plugin = clsIt->second.first; } // fi return( plugin ); } // ------------------------------------------------------------------------- std::string cpPlugins::Interface:: GetPluginName( const ProcessObject* obj ) const { if( obj != NULL ) return( this->GetPluginName( obj->GetClassCategory( ), obj->GetClassName( ) ) ); else return( "" ); } // ------------------------------------------------------------------------- std::set< std::string > cpPlugins::Interface:: GetPlugins( ) const { std::set< std::string > res; auto i = this->m_DynLibraries.begin( ); for( ; i != this->m_DynLibraries.end( ); ++i ) res.insert( i->first ); return( res ); } // ------------------------------------------------------------------------- void* cpPlugins::Interface:: _DLOpen( const std::string& fname ) { void* hnd = NULL; #ifdef cpPlugins_SYS_WINDOWS hnd = ::LoadLibraryA( fname.c_str( ) ); #else // cpPlugins_SYS_WINDOWS hnd = dlopen( fname.c_str( ), RTLD_NOW | RTLD_GLOBAL ); dlerror( ); #endif // cpPlugins_SYS_WINDOWS return( hnd ); } // ------------------------------------------------------------------------- const char* cpPlugins::Interface:: _DLGetName( void* hnd ) { // Get descriptors typedef const char* ( *f_t )( ); f_t f = NULL; #ifdef cpPlugins_SYS_WINDOWS f = ( f_t )( ::GetProcAddress( ( HMODULE )hnd, "cpPlugins_Name" ) ); #else // cpPlugins_SYS_WINDOWS f = ( f_t )( dlsym( hnd, "cpPlugins_Name" ) ); #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( f( ) ); } // ------------------------------------------------------------------------- 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 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$