TuttleOFX
1
|
00001 /* 00002 * Software License : 00003 * 00004 * Copyright (c) 2007-2009, The Open Effects Association Ltd. All Rights Reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * 00009 * Redistributions of source code must retain the above copyright notice, 00010 * this list of conditions and the following disclaimer. 00011 * Redistributions in binary form must reproduce the above copyright notice, 00012 * this list of conditions and the following disclaimer in the documentation 00013 * and/or other materials provided with the distribution. 00014 * Neither the name The Open Effects Association Ltd, nor the names of its 00015 * contributors may be used to endorse or promote products derived from this 00016 * software without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00019 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00020 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00021 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 00022 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00023 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00024 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 00025 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00026 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00027 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 #ifndef _TUTTLE_HOST_OFX_PLUGINCACHE_HPP_ 00030 #define _TUTTLE_HOST_OFX_PLUGINCACHE_HPP_ 00031 00032 #include "property/OfxhSet.hpp" 00033 #include "OfxhPluginAPICache.hpp" 00034 #include "OfxhPluginBinary.hpp" 00035 00036 #include <ofxCore.h> 00037 00038 #include <boost/serialization/string.hpp> 00039 #include <boost/serialization/set.hpp> 00040 #include <boost/serialization/list.hpp> 00041 #include <boost/ptr_container/serialize_ptr_list.hpp> 00042 00043 #include <string> 00044 #include <set> 00045 #include <algorithm> 00046 #include <iostream> 00047 00048 namespace tuttle { 00049 namespace host { 00050 namespace ofx { 00051 00052 /** 00053 * for later 00054 */ 00055 struct PluginCacheSupportedApi 00056 { 00057 APICache::OfxhPluginAPICacheI* _handler; 00058 00059 PluginCacheSupportedApi( APICache::OfxhPluginAPICacheI* handler ) 00060 : _handler( handler ) {} 00061 00062 bool matches( std::string api, int version ) const 00063 { 00064 if( api == _handler->_apiName && version >= _handler->_apiVersionMin && version <= _handler->_apiVersionMax ) 00065 { 00066 return true; 00067 } 00068 return false; 00069 } 00070 00071 }; 00072 00073 /** 00074 * Where we keep our plugins. 00075 */ 00076 class OfxhPluginCache 00077 { 00078 public: 00079 typedef OfxhPluginCache This; 00080 typedef boost::ptr_list<OfxhPluginBinary> OfxhPluginBinaryList; 00081 00082 protected: 00083 tuttle::host::ofx::property::OfxhPropSpec* _hostSpec; 00084 00085 std::list<std::string> _pluginPath; ///< list of directories to look in 00086 std::set<std::string> _nonrecursePath; ///< list of directories to look in (non-recursively) 00087 std::list<std::string> _pluginDirs; ///< list of directories we found 00088 OfxhPluginBinaryList _binaries; ///< all the binaries we know about, we own these 00089 std::list<OfxhPlugin*> _plugins; ///< all the plugins inside the binaries, we don't own these, populated from _binaries 00090 std::map<std::string, OfxhPlugin*> _pluginsByID; 00091 std::map<OfxhPluginIdent, bool> _loadedMap; ///< Used to check if a plugin is loaded twice 00092 std::set<std::string> _knownBinFiles; 00093 00094 std::list<PluginCacheSupportedApi> _apiHandlers; 00095 00096 // internal state 00097 bool _ignoreCache; 00098 std::string _cacheVersion; 00099 bool _dirty; 00100 bool _enablePluginSeek; ///< Turn off to make all seekPluginFile() calls return an empty string 00101 00102 public: 00103 /// ctor, which inits _pluginPath to default locations and not much else 00104 OfxhPluginCache(); 00105 00106 /// dtor 00107 ~OfxhPluginCache(); 00108 00109 protected: 00110 void scanDirectory( std::set<std::string>& foundBinFiles, const std::string& dir, bool recurse ); 00111 00112 void addPlugin( OfxhPlugin* plugin ) 00113 { 00114 // Check if the same plugin has already been loaded 00115 if( _loadedMap.find( plugin->getIdentity() ) == _loadedMap.end() ) 00116 { 00117 _loadedMap[plugin->getIdentity()] = true; 00118 } 00119 else 00120 { 00121 TUTTLE_LOG_WARNING( "Plugin: " << plugin->getRawIdentifier() << " loaded twice! (" << plugin->getBinary().getFilePath() << ")" ); 00122 } 00123 _plugins.push_back( plugin ); 00124 00125 if( _pluginsByID.find( plugin->getIdentifier() ) != _pluginsByID.end() ) 00126 { 00127 OfxhPlugin& otherPlugin = *_pluginsByID[plugin->getIdentifier()]; 00128 if( plugin->trumps( otherPlugin ) ) 00129 { 00130 _pluginsByID[plugin->getIdentifier()] = plugin; 00131 } 00132 } 00133 else 00134 { 00135 _pluginsByID[plugin->getIdentifier()] = plugin; 00136 } 00137 } 00138 00139 public: 00140 friend std::ostream& operator<<( std::ostream& os, const This& g ); 00141 00142 public: 00143 /// get the plugin by id. vermaj and vermin can be specified. if they are not it will 00144 /// pick the highest found version. 00145 OfxhPlugin* getPluginById( const std::string& id, int vermaj = -1, int vermin = -1 ); 00146 const OfxhPlugin* getPluginById( const std::string& id, int vermaj = -1, int vermin = -1 ) const { return const_cast<This&>( *this ).getPluginById( id, vermaj, vermin ); } 00147 00148 /// get the list in which plugins are sought 00149 const std::list<std::string>& getPluginPath() 00150 { 00151 return _pluginPath; 00152 } 00153 00154 /// was the cache outdated? 00155 bool isDirty() const 00156 { 00157 return _dirty; 00158 } 00159 00160 void setDirty() 00161 { 00162 //TUTTLE_TLOG( TUTTLE_INFO, "OfxhPluginCache::setDirty()" ); 00163 _dirty = true; 00164 } 00165 00166 /// add a directory to the plugin path 00167 void addDirectoryToPath( const std::string& f, bool recurse = true ) 00168 { 00169 _pluginPath.push_back( f ); 00170 if( !recurse ) 00171 { 00172 _nonrecursePath.insert( f ); 00173 } 00174 } 00175 00176 /// specify which subdirectory of /usr/OFX or equivilant 00177 /// (as well as 'Plugins') to look in for plugins. 00178 void setPluginHostPath( const std::string& hostId ); 00179 00180 /// set the version string to write to the cache, 00181 /// and also that we expect on cachess read in 00182 void setCacheVersion( const std::string& cacheVersion ) 00183 { 00184 _cacheVersion = cacheVersion; 00185 } 00186 00187 // populate the cache. must call scanPluginFiles() after to check for changes. 00188 //void readCache( std::istream& is ); 00189 00190 // seek a particular file on the OFX plugin path 00191 std::string seekPluginFile( const std::string& baseName ) const; 00192 00193 /// Sets behaviour of seekPluginFile(). 00194 /// Enable (the default): normal operation; disable: returns an empty string instead 00195 void setPluginSeekEnabled( bool enabled ) 00196 { 00197 _enablePluginSeek = enabled; 00198 } 00199 00200 /// scan for plugins 00201 void scanPluginFiles(); 00202 00203 /// register an API cache handler 00204 void registerAPICache( APICache::OfxhPluginAPICacheI& apiCache ) 00205 { 00206 _apiHandlers.push_back( PluginCacheSupportedApi( &apiCache ) ); 00207 } 00208 00209 /// find the API cache handler for the given api/apiverson 00210 APICache::OfxhPluginAPICacheI* findApiHandler( const std::string& api, int apiver ); 00211 00212 /// obtain a list of plugins to walk through 00213 const std::list<OfxhPlugin*>& getPlugins() const 00214 { 00215 return _plugins; 00216 } 00217 00218 OfxhPluginBinaryList& getBinaries() 00219 { 00220 return _binaries; 00221 } 00222 00223 private: 00224 friend class boost::serialization::access; 00225 template<class Archive> 00226 void serialize( Archive& ar, const unsigned int version ) 00227 { 00228 // ar & BOOST_SERIALIZATION_NVP(_pluginPath); 00229 // ar & BOOST_SERIALIZATION_NVP(_nonrecursePath); 00230 // ar & BOOST_SERIALIZATION_NVP(_pluginDirs); 00231 ar& BOOST_SERIALIZATION_NVP( _binaries ); 00232 // ar & BOOST_SERIALIZATION_NVP(_plugins); // just a link, don't save this 00233 ar& BOOST_SERIALIZATION_NVP( _knownBinFiles ); 00234 00235 if( typename Archive::is_loading() ) 00236 { 00237 for( ofx::OfxhPluginCache::OfxhPluginBinaryList::iterator it = getBinaries().begin(), itEnd = getBinaries().end(); 00238 it != itEnd; 00239 ++it ) 00240 { 00241 for( ofx::OfxhPluginBinary::PluginVector::iterator i = it->getPlugins().begin(), iEnd = it->getPlugins().end(); 00242 i != iEnd; 00243 ++i ) 00244 { 00245 APICache::OfxhPluginAPICacheI* apiCache = findApiHandler( i->getPluginApi(), i->getApiVersion() ); 00246 i->setApiHandler( *apiCache ); 00247 _plugins.push_back( &( *i ) ); 00248 } 00249 } 00250 } 00251 } 00252 00253 }; 00254 00255 } 00256 } 00257 } 00258 00259 #endif