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 "compressorInfo.h"
24 : #include "log.h"
25 : #include "plugin.h"
26 : #include "pluginVisitor.h"
27 :
28 : #include <lunchbox/algorithm.h>
29 : #include <lunchbox/debug.h>
30 : #include <lunchbox/file.h>
31 :
32 : #ifdef _WIN32
33 : # include <lunchbox/os.h> // GetModuleFileName
34 : # include <direct.h>
35 : # define getcwd _getcwd
36 : #else
37 : # include <unistd.h> // for getcwd
38 : #endif
39 :
40 : #ifndef MAXPATHLEN
41 : # define MAXPATHLEN 1024
42 : #endif
43 :
44 : namespace pression
45 : {
46 : namespace detail
47 : {
48 : class PluginRegistry
49 : {
50 : public:
51 1 : PluginRegistry()
52 1 : {
53 1 : char* env = getenv( "EQ_PLUGIN_PATH" );
54 2 : std::string envString( env ? env : "" );
55 :
56 1 : if( envString.empty( ))
57 : {
58 : char cwd[MAXPATHLEN];
59 1 : directories.push_back( getcwd( cwd, MAXPATHLEN ));
60 :
61 : #ifdef _WIN32
62 : if( GetModuleFileName( 0, cwd, MAXPATHLEN ) > 0 )
63 : directories.push_back( lunchbox::getDirname( cwd ));
64 : #else
65 : # ifdef Darwin
66 : env = getenv( "DYLD_LIBRARY_PATH" );
67 : # else
68 1 : env = getenv( "LD_LIBRARY_PATH" );
69 : # endif
70 1 : if( env )
71 1 : envString = env;
72 : # endif
73 : }
74 :
75 : #ifdef _WIN32
76 : const char separator = ';';
77 : #else
78 1 : const char separator = ':';
79 : #endif
80 :
81 49 : while( !envString.empty( ))
82 : {
83 24 : size_t nextPos = envString.find( separator );
84 24 : if ( nextPos == std::string::npos )
85 1 : nextPos = envString.size();
86 :
87 48 : std::string path = envString.substr( 0, nextPos );
88 24 : if ( nextPos == envString.size( ))
89 1 : envString = "";
90 : else
91 23 : envString = envString.substr( nextPos + 1, envString.size() );
92 :
93 24 : if( !path.empty( ))
94 24 : directories.push_back( path );
95 : }
96 1 : }
97 :
98 1 : ~PluginRegistry()
99 1 : {
100 1 : LBASSERTINFO( plugins.empty(), "Plugin registry not de-initialized" );
101 1 : }
102 :
103 : Strings directories;
104 : Plugins plugins;
105 : };
106 : }
107 :
108 1 : PluginRegistry::PluginRegistry()
109 1 : : impl_( new detail::PluginRegistry )
110 1 : {}
111 :
112 2 : PluginRegistry::~PluginRegistry()
113 : {
114 1 : delete impl_;
115 1 : }
116 :
117 9 : const Strings& PluginRegistry::getDirectories() const
118 : {
119 9 : return impl_->directories;
120 : }
121 :
122 9 : void PluginRegistry::addDirectory( const std::string& path )
123 : {
124 9 : impl_->directories.push_back( path );
125 9 : }
126 :
127 0 : void PluginRegistry::removeDirectory( const std::string& path )
128 : {
129 0 : Strings::iterator i = lunchbox::find( impl_->directories, path );
130 0 : if( i != impl_->directories.end( ))
131 0 : impl_->directories.erase( i );
132 0 : }
133 :
134 1 : bool PluginRegistry::addLunchboxPlugins()
135 : {
136 : #ifdef PRESSION_DSO_NAME
137 : return
138 4 : addPlugin( PRESSION_DSO_NAME ) || // Found by LDD
139 : // Hard-coded compile locations as backup:
140 1 : addPlugin( std::string( PRESSION_BUILD_DIR ) + "lib/" +
141 3 : PRESSION_DSO_NAME ) ||
142 : # ifdef NDEBUG
143 : addPlugin( std::string( PRESSION_BUILD_DIR ) +
144 : "lib/Release/" + PRESSION_DSO_NAME )
145 : # else
146 1 : addPlugin( std::string( PRESSION_BUILD_DIR ) + "lib/Debug/" +
147 1 : PRESSION_DSO_NAME )
148 : # endif
149 : ;
150 : #endif
151 : return false;
152 : }
153 :
154 1 : void PluginRegistry::init()
155 : {
156 : // for each directory
157 105 : for( StringsCIter i = impl_->directories.begin();
158 70 : i != impl_->directories.end(); ++i )
159 : {
160 34 : const std::string& dir = *i;
161 34 : LBLOG( LOG_PLUGIN ) << "Searching plugins in " << dir << std::endl;
162 :
163 : #ifdef _WIN32
164 : const Strings& files =
165 : lunchbox::searchDirectory( dir, ".*Compressor.*\\.dll" );
166 : const char DIRSEP = '\\';
167 : #elif defined (Darwin)
168 : const Strings& files =
169 : lunchbox::searchDirectory( dir, "lib.*Compressor.*\\.dylib" );
170 : const char DIRSEP = '/';
171 : #else
172 : const Strings& files =
173 68 : lunchbox::searchDirectory( dir, "lib.*Compressor.*\\.so" );
174 34 : const char DIRSEP = '/';
175 : #endif
176 : // for each file found in the directory
177 34 : for( StringsCIter j = files.begin(); j != files.end(); ++j )
178 : {
179 : // build path + name of library
180 0 : const std::string libraryName = dir.empty() ? *j : dir+DIRSEP+*j;
181 0 : addPlugin( libraryName );
182 : }
183 : }
184 1 : }
185 :
186 : namespace
187 : {
188 1 : Plugin* _loadPlugin( const std::string& filename, const Strings& directories )
189 : {
190 1 : if( filename.size() < 3 )
191 0 : return 0;
192 :
193 1 : Plugin* plugin = new Plugin( filename );
194 1 : if( plugin->isGood( ))
195 1 : return plugin;
196 0 : delete plugin;
197 :
198 0 : if( filename[0] == '/' || filename[1] == ':' /* Win drive letter */ )
199 0 : return 0;
200 :
201 0 : for( StringsCIter i = directories.begin(); i != directories.end(); ++i )
202 : {
203 0 : const std::string& dir = *i;
204 0 : plugin = new Plugin( dir + "/" + filename );
205 0 : if( plugin->isGood( ))
206 0 : return plugin;
207 0 : delete plugin;
208 : }
209 0 : return 0;
210 : }
211 : }
212 :
213 1 : bool PluginRegistry::addPlugin( const std::string& filename )
214 : {
215 1 : Plugin* plugin = _loadPlugin( filename, impl_->directories );
216 1 : if( !plugin )
217 0 : return false;
218 :
219 1 : const CompressorInfos& infos = plugin->getInfos();
220 1 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i)
221 : {
222 0 : const CompressorInfos& infos2 = (*i)->getInfos();
223 :
224 : // Simple test to avoid loading the same dll twice
225 0 : if( infos.front().name == infos2.front().name )
226 : {
227 0 : delete plugin;
228 0 : return true;
229 : }
230 : }
231 :
232 1 : impl_->plugins.push_back( plugin );
233 1 : LBLOG( LOG_PLUGIN ) << "Found " << plugin->getInfos().size()
234 1 : << " compression engines in " << filename << std::endl;
235 1 : return true;
236 : }
237 :
238 1 : void PluginRegistry::exit()
239 : {
240 2 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i)
241 : {
242 1 : Plugin* plugin = *i;
243 1 : delete plugin;
244 : }
245 :
246 1 : impl_->plugins.clear();
247 1 : }
248 :
249 : namespace
250 : {
251 370 : template< class P, class I > class Finder : public PluginVisitorT< P, I >
252 : {
253 : public:
254 370 : explicit Finder( const uint32_t name ) : plugin( 0 ), name_( name ) {}
255 6956 : virtual VisitorResult visit( P& candidate, I& info )
256 : {
257 6956 : if( info.name != name_ )
258 6586 : return TRAVERSE_CONTINUE;
259 :
260 370 : plugin = &candidate;
261 370 : return TRAVERSE_TERMINATE;
262 : }
263 :
264 : P* plugin;
265 : private:
266 : const uint32_t name_;
267 : };
268 : }
269 :
270 370 : Plugin* PluginRegistry::findPlugin( const uint32_t name )
271 : {
272 740 : Finder< Plugin, EqCompressorInfo > finder( name );
273 370 : accept( finder );
274 740 : return finder.plugin;
275 : }
276 :
277 0 : const Plugin* PluginRegistry::findPlugin( const uint32_t name ) const
278 : {
279 0 : Finder< const Plugin, const EqCompressorInfo > finder( name );
280 0 : accept( finder );
281 0 : return finder.plugin;
282 : }
283 :
284 370 : VisitorResult PluginRegistry::accept( PluginVisitor& visitor )
285 : {
286 370 : VisitorResult result = TRAVERSE_CONTINUE;
287 370 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i )
288 370 : switch( (*i)->accept( visitor ))
289 : {
290 : case TRAVERSE_TERMINATE:
291 370 : return TRAVERSE_TERMINATE;
292 : case TRAVERSE_PRUNE:
293 0 : result = TRAVERSE_PRUNE;
294 : default:
295 0 : break;
296 : }
297 :
298 0 : return result;
299 : }
300 0 : VisitorResult PluginRegistry::accept( ConstPluginVisitor& visitor ) const
301 : {
302 0 : VisitorResult result = TRAVERSE_CONTINUE;
303 0 : for( PluginsCIter i = impl_->plugins.begin(); i != impl_->plugins.end(); ++i )
304 0 : switch( (*i)->accept( visitor ))
305 : {
306 : case TRAVERSE_TERMINATE:
307 0 : return TRAVERSE_TERMINATE;
308 : case TRAVERSE_PRUNE:
309 0 : result = TRAVERSE_PRUNE;
310 : case TRAVERSE_CONTINUE:
311 0 : break;
312 : }
313 :
314 0 : return result;
315 : }
316 :
317 2 : const Plugins& PluginRegistry::getPlugins() const
318 : {
319 2 : return impl_->plugins;
320 : }
321 :
322 3 : }
|