Line data Source code
1 :
2 : /* Copyright (c) 2009, Cedric Stalder <cedric.stalder@gmail.com>
3 : * 2010-2013, Stefan Eilemann <eile@eyescale.ch>
4 : *
5 : * This file is part of Collage <https://github.com/Eyescale/Collage>
6 : *
7 : * This library is free software; you can redistribute it and/or modify it under
8 : * the terms of the GNU Lesser General Public License version 2.1 as published
9 : * by the Free Software Foundation.
10 : *
11 : * This library is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 : * details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with this library; if not, write to the Free Software Foundation, Inc.,
18 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 :
21 : #include "pluginRegistry.h"
22 :
23 : #include "algorithm.h"
24 : #include "compressorInfo.h"
25 : #include "debug.h"
26 : #include "file.h"
27 : #include "log.h"
28 : #include "plugin.h"
29 : #include "pluginVisitor.h"
30 :
31 : #ifdef _WIN32
32 : # include "os.h" // GetModuleFileName
33 : # include <direct.h>
34 : # define getcwd _getcwd
35 : #else
36 : # include <unistd.h> // for getcwd
37 : #endif
38 :
39 : #ifndef MAXPATHLEN
40 : # define MAXPATHLEN 1024
41 : #endif
42 :
43 : namespace lunchbox
44 : {
45 : namespace detail
46 : {
47 : class PluginRegistry
48 : {
49 : public:
50 1 : PluginRegistry()
51 1 : {
52 1 : char* env = getenv( "EQ_PLUGIN_PATH" );
53 1 : std::string envString( env ? env : "" );
54 :
55 1 : if( envString.empty( ))
56 : {
57 : char cwd[MAXPATHLEN];
58 1 : directories.push_back( getcwd( cwd, MAXPATHLEN ));
59 :
60 : #ifdef _WIN32
61 : if( GetModuleFileName( 0, cwd, MAXPATHLEN ) > 0 )
62 : directories.push_back( lunchbox::getDirname( cwd ));
63 : #else
64 : # ifdef Darwin
65 : env = getenv( "DYLD_LIBRARY_PATH" );
66 : # else
67 1 : env = getenv( "LD_LIBRARY_PATH" );
68 : # endif
69 1 : if( env )
70 1 : envString = env;
71 : # endif
72 : }
73 :
74 : #ifdef _WIN32
75 : const char separator = ';';
76 : #else
77 1 : const char separator = ':';
78 : #endif
79 :
80 4 : while( !envString.empty( ))
81 : {
82 2 : size_t nextPos = envString.find( separator );
83 2 : if ( nextPos == std::string::npos )
84 1 : nextPos = envString.size();
85 :
86 2 : std::string path = envString.substr( 0, nextPos );
87 2 : if ( nextPos == envString.size( ))
88 1 : envString = "";
89 : else
90 1 : envString = envString.substr( nextPos + 1, envString.size() );
91 :
92 2 : if( !path.empty( ))
93 1 : directories.push_back( path );
94 3 : }
95 1 : }
96 :
97 1 : ~PluginRegistry()
98 1 : {
99 1 : LBASSERTINFO( plugins.empty(), "Plugin registry not de-initialized" );
100 1 : }
101 :
102 : Strings directories;
103 : Plugins plugins;
104 : };
105 : }
106 :
107 1 : PluginRegistry::PluginRegistry()
108 1 : : impl_( new detail::PluginRegistry )
109 1 : {}
110 :
111 1 : PluginRegistry::~PluginRegistry()
112 : {
113 1 : delete impl_;
114 1 : }
115 :
116 14 : const Strings& PluginRegistry::getDirectories() const
117 : {
118 14 : return impl_->directories;
119 : }
120 :
121 1 : void PluginRegistry::addDirectory( const std::string& path )
122 : {
123 1 : impl_->directories.push_back( path );
124 1 : }
125 :
126 0 : void PluginRegistry::removeDirectory( const std::string& path )
127 : {
128 0 : Strings::iterator i = find( impl_->directories, path );
129 0 : if( i != impl_->directories.end( ))
130 0 : impl_->directories.erase( i );
131 0 : }
132 :
133 1 : bool PluginRegistry::addLunchboxPlugins()
134 : {
135 : #ifdef LUNCHBOX_DSO_NAME
136 : return
137 4 : addPlugin( LUNCHBOX_DSO_NAME ) || // Found by LDD
138 : // Hard-coded compile locations as backup:
139 1 : addPlugin( std::string( LUNCHBOX_BUILD_DIR ) + "lib/" +
140 3 : LUNCHBOX_DSO_NAME ) ||
141 : # ifdef NDEBUG
142 : addPlugin( std::string( LUNCHBOX_BUILD_DIR ) +
143 : "lib/Release/" + LUNCHBOX_DSO_NAME )
144 : # else
145 1 : addPlugin( std::string( LUNCHBOX_BUILD_DIR ) + "lib/Debug/" +
146 1 : LUNCHBOX_DSO_NAME )
147 : # endif
148 : ;
149 : #endif
150 : return false;
151 : }
152 :
153 1 : void PluginRegistry::init()
154 : {
155 : // for each directory
156 12 : for( StringsCIter i = impl_->directories.begin();
157 8 : i != impl_->directories.end(); ++i )
158 : {
159 3 : const std::string& dir = *i;
160 3 : LBLOG( LOG_PLUGIN ) << "Searching plugins in " << dir << std::endl;
161 :
162 : #ifdef _WIN32
163 : const Strings& files = searchDirectory( dir, ".*Compressor.*\\.dll" );
164 : const char DIRSEP = '\\';
165 : #elif defined (Darwin)
166 : const Strings& files = searchDirectory( dir,
167 : "lib.*Compressor.*\\.dylib" );
168 : const char DIRSEP = '/';
169 : #else
170 3 : const Strings& files = searchDirectory( dir, "lib.*Compressor.*\\.so" );
171 3 : const char DIRSEP = '/';
172 : #endif
173 : // for each file found in the directory
174 3 : for( StringsCIter j = files.begin(); j != files.end(); ++j )
175 : {
176 : // build path + name of library
177 0 : const std::string libraryName = dir.empty() ? *j : dir+DIRSEP+*j;
178 0 : addPlugin( libraryName );
179 0 : }
180 3 : }
181 1 : }
182 :
183 : namespace
184 : {
185 1 : Plugin* _loadPlugin( const std::string& filename, const Strings& directories )
186 : {
187 1 : if( filename.size() < 3 )
188 0 : return 0;
189 :
190 1 : Plugin* plugin = new Plugin( filename );
191 1 : if( plugin->isGood( ))
192 1 : return plugin;
193 0 : delete plugin;
194 :
195 0 : if( filename[0] == '/' || filename[1] == ':' /* Win drive letter */ )
196 0 : return 0;
197 :
198 0 : for( StringsCIter i = directories.begin(); i != directories.end(); ++i )
199 : {
200 0 : const std::string& dir = *i;
201 0 : plugin = new Plugin( dir + "/" + filename );
202 0 : if( plugin->isGood( ))
203 0 : return plugin;
204 0 : delete plugin;
205 : }
206 0 : return 0;
207 : }
208 : }
209 :
210 1 : bool PluginRegistry::addPlugin( const std::string& filename )
211 : {
212 1 : Plugin* plugin = _loadPlugin( filename, impl_->directories );
213 1 : if( !plugin )
214 0 : return false;
215 :
216 1 : const CompressorInfos& infos = plugin->getInfos();
217 1 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i)
218 : {
219 0 : const CompressorInfos& infos2 = (*i)->getInfos();
220 :
221 : // Simple test to avoid loading the same dll twice
222 0 : if( infos.front().name == infos2.front().name )
223 : {
224 0 : delete plugin;
225 0 : return true;
226 : }
227 : }
228 :
229 1 : impl_->plugins.push_back( plugin );
230 1 : LBLOG( LOG_PLUGIN ) << "Found " << plugin->getInfos().size()
231 1 : << " compression engines in " << filename << std::endl;
232 1 : return true;
233 : }
234 :
235 1 : void PluginRegistry::exit()
236 : {
237 2 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i)
238 : {
239 1 : Plugin* plugin = *i;
240 1 : delete plugin;
241 : }
242 :
243 1 : impl_->plugins.clear();
244 1 : }
245 :
246 : namespace
247 : {
248 304 : template< class P, class I > class Finder : public PluginVisitorT< P, I >
249 : {
250 : public:
251 304 : explicit Finder( const uint32_t name ) : plugin( 0 ), name_( name ) {}
252 4104 : virtual VisitorResult visit( P& candidate, I& info )
253 : {
254 4104 : if( info.name != name_ )
255 3800 : return TRAVERSE_CONTINUE;
256 :
257 304 : plugin = &candidate;
258 304 : return TRAVERSE_TERMINATE;
259 : }
260 :
261 : P* plugin;
262 : private:
263 : const uint32_t name_;
264 : };
265 : }
266 :
267 304 : Plugin* PluginRegistry::findPlugin( const uint32_t name )
268 : {
269 304 : Finder< Plugin, EqCompressorInfo > finder( name );
270 304 : accept( finder );
271 304 : return finder.plugin;
272 : }
273 :
274 0 : const Plugin* PluginRegistry::findPlugin( const uint32_t name ) const
275 : {
276 0 : Finder< const Plugin, const EqCompressorInfo > finder( name );
277 0 : accept( finder );
278 0 : return finder.plugin;
279 : }
280 :
281 304 : VisitorResult PluginRegistry::accept( PluginVisitor& visitor )
282 : {
283 304 : VisitorResult result = TRAVERSE_CONTINUE;
284 304 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i )
285 304 : switch( (*i)->accept( visitor ))
286 : {
287 : case TRAVERSE_TERMINATE:
288 304 : return TRAVERSE_TERMINATE;
289 : case TRAVERSE_PRUNE:
290 0 : result = TRAVERSE_PRUNE;
291 : default:
292 0 : break;
293 : }
294 :
295 0 : return result;
296 : }
297 0 : VisitorResult PluginRegistry::accept( ConstPluginVisitor& visitor ) const
298 : {
299 0 : VisitorResult result = TRAVERSE_CONTINUE;
300 0 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i )
301 0 : switch( (*i)->accept( visitor ))
302 : {
303 : case TRAVERSE_TERMINATE:
304 0 : return TRAVERSE_TERMINATE;
305 : case TRAVERSE_PRUNE:
306 0 : result = TRAVERSE_PRUNE;
307 : case TRAVERSE_CONTINUE:
308 0 : break;
309 : }
310 :
311 0 : return result;
312 : }
313 :
314 2 : const Plugins& PluginRegistry::getPlugins() const
315 : {
316 2 : return impl_->plugins;
317 : }
318 :
319 90 : }
|