/* $Id$ */ /* * Cantus Tag Editor * Copyright © 2002-2004 by Samuel Abels * Copyright © 2007 by Tim Huetz * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see **/ /* needed includes for this file */ #include CantusPlugin::CantusPlugin() { this->m_refCounter = 1; this->m_dlHandle = NULL; this->m_pluginData = cantushash_create(); cantushash_set_pointer( this->m_pluginData, "Cantus:AddListener", (gpointer)&eventbus_add_listener ); cantushash_set_pointer( this->m_pluginData, "Cantus:AddListenerSigC", (gpointer)&eventbus_add_listener_sigc ); cantushash_set_pointer( this->m_pluginData, "Cantus:RemoveListener", (gpointer)&eventbus_remove_listener ); cantushash_set_pointer( this->m_pluginData, "Cantus:Emit", (gpointer)&eventbus_emit ); cantushash_set_pointer( this->m_pluginData, "Cantus:PrefSet_int", (gpointer)&preferences_set_int ); cantushash_set_pointer( this->m_pluginData, "Cantus:PrefGet_int", (gpointer)&preferences_get_int ); cantushash_set_pointer( this->m_pluginData, "Cantus:PrefSet_bool", (gpointer)&preferences_set_bool ); cantushash_set_pointer( this->m_pluginData, "Cantus:PrefGet_bool", (gpointer)&preferences_get_bool ); cantushash_set_pointer( this->m_pluginData, "Cantus:PrefSet_char", (gpointer)&preferences_set_char ); cantushash_set_pointer( this->m_pluginData, "Cantus:PrefGet_char", (gpointer)&preferences_get_char ); cantushash_set_pointer( this->m_pluginData, "Cantus:FileInfoGet", (gpointer)&fileinfomanager_get_info ); cantushash_set_pointer( this->m_pluginData, "Cantus:FileInfoUnlock", (gpointer)&fileinfomanager_unlock_info ); } CantusPlugin::~CantusPlugin() { DestroyFunc func = (DestroyFunc)cantushash_get_pointer( this->m_pluginData, "Plugin:DestroyFunc" ); if( NULL != func ) { gint err = func(); } else { g_warning( "Plugin '%s' has no destructor!\n", this->getName() ); } if( NULL != this->m_dlHandle ) { dlclose( this->m_dlHandle ); this->m_dlHandle = NULL; } cantushash_destroy( this->m_pluginData ); } gint CantusPlugin::loadPlugin( const gchar * filename ) { if( !( this->m_dlHandle = dlopen( filename, RTLD_LAZY ) ) ) { std::cerr << "Cannot open library: " << dlerror() << '\n'; return -1; } /* specify which symbols to load */ Symbol symbols[] = { { "plugin_destroy", "Plugin:DestroyFunc", TRUE }, { "plugin_handles", "Plugin:HandlesFunc", FALSE }, { "plugin_read", "Plugin:ReadFunc", FALSE }, { "plugin_write", "Plugin:WriteFunc", FALSE }, { "plugin_get_uiwidget", "Plugin:UIWidgetFunc", FALSE }, { "plugin_get_uiprefs", "Plugin:UIPrefsFunc", FALSE }, { "plugin_get_uiicon", "Plugin:UIIconFunc", FALSE }, { NULL, NULL, 0 } }; /* load the initializer symbol */ AnyFunc func; if( !( func = (AnyFunc)dlsym( this->m_dlHandle, "plugin_init" ) ) ) { std::cerr << "Cannot load symbol 'plugin_init': " << dlerror() << '\n'; dlclose( this->m_dlHandle ); return -11; } // Call the initializer. gint err = ( (InitFunc)func )( this->m_pluginData ); if( err != 0 ) { std::cerr << "Error: Plugin initializer returned error " << err << ".\n"; dlclose( this->m_dlHandle ); return -31; } /* load all symbols */ gint i = -1; while( symbols[ ++i ].name ) { func = (AnyFunc)dlsym( this->m_dlHandle, symbols[ i ].name ); if( symbols[ i ].required && !func ) { std::cerr << "Cannot load mandatory symbol '" << symbols[i].name << "': " << dlerror() << '\n'; dlclose( this->m_dlHandle ); return -51; } cantushash_set_pointer( this->m_pluginData, symbols[ i ].keyname, (void*)func ); } /* plugin validity check */ if( !this->checkPlugin() ) { std::cerr << "Error: Plugin validity check failed.\n"; dlclose( this->m_dlHandle ); return -41; } /* anything ok */ return 0; } void CantusPlugin::ref() { this->m_refCounter++; } void CantusPlugin::unref() { this->m_refCounter--; if( this->m_refCounter > 0 ) { return; } this->signalPluginDeleted.emit( this ); delete( this ); } void CantusPlugin::setPriority( gint prio ) { this->m_pluginPriority = prio; } gint CantusPlugin::getPriority() { return( this->m_pluginPriority ); } const gchar *CantusPlugin::getName() { return( cantushash_get_char( this->m_pluginData, "Plugin:Name" ) ); } const gchar *CantusPlugin::getTagname() { return( cantushash_get_char( this->m_pluginData, "Plugin:TagName" ) ); } const gchar *CantusPlugin::getLabel() { return( cantushash_get_char( this->m_pluginData, "Plugin:Label" ) ); } const gchar *CantusPlugin::getDescription() { return( cantushash_get_char( this->m_pluginData, "Plugin:Description" ) ); } gint CantusPlugin::getMajorVersion() { return( cantushash_get_int( this->m_pluginData, "Plugin:MajorVersion" ) ); } gint CantusPlugin::getMinorVersion() { return( cantushash_get_int( this->m_pluginData, "Plugin:MinorVersion" ) ); } const ReadFunc CantusPlugin::getReadFunction() { return( (ReadFunc)cantushash_get_pointer( this->m_pluginData, "Plugin:ReadFunc" ) ); } const WriteFunc CantusPlugin::getWriteFunction() { return( (WriteFunc)cantushash_get_pointer( this->m_pluginData, "Plugin:WriteFunc" ) ); } gint CantusPlugin::isHandling( const gchar *filename ) { HandlesFunc handles = (HandlesFunc)cantushash_get_pointer( this->m_pluginData, "Plugin:HandlesFunc" ); if( !filename || *filename == '\0' || !handles ) { return( FALSE ); } const gchar ** pattern = (const gchar**)cantushash_get_pointer( this->m_pluginData, "Plugin:Pattern" ); if( !shellpattern_match_any( filename, pattern, FALSE ) ) { return( FALSE ); } return( TRUE ); } void *CantusPlugin::getUIWidget(gboolean vertical) { UIWidgetFunc func = (UIWidgetFunc)cantushash_get_pointer( this->m_pluginData, "Plugin:UIWidgetFunc" ); g_assert( func != NULL ); return( func( vertical ) ); } gboolean CantusPlugin::checkPlugin() { gint compat = cantushash_get_int( this->m_pluginData, "Plugin:CompatibilityLevel" ); if( compat > PLUGIN_COMPAT_LEVEL ) { std::cerr << "Error: Incompatible plugin.\n"; return( FALSE ); } if( !cantushash_get_pointer( this->m_pluginData, "Plugin:Pattern" ) ) { std::cerr << "Error: Plugin did not specify a filename pattern.\n"; return( FALSE ); } if( *( this->getName() ) == '\0' ) { std::cerr << "Error: Initializer returned an emtpy name.\n"; return( FALSE ); } if( strlen( this->getDescription() ) > 200 ) { g_warning( "Plugin::get_description(): Description < 200 chars failed.\n" ); } if( cantushash_get_pointer( this->m_pluginData, "Plugin:UIPrefsFunc" ) && !cantushash_get_pointer( this->m_pluginData, "Plugin:UIIconFunc" ) ) { std::cerr << "Error: Plugin has preferences but did not specify an icon\n."; return( FALSE ); } /* anything ok */ return( TRUE ); }