author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Tue, 02 Feb 2010 00:43:10 +0200 | |
changeset 3 | 41300fa6a67c |
parent 0 | 1918ee327afb |
child 30 | 5dc02b23752f |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
|
3 |
* Copyright (C) 2008 Collabora, Ltd. All rights reserved. |
|
4 |
* |
|
5 |
* Redistribution and use in source and binary forms, with or without |
|
6 |
* modification, are permitted provided that the following conditions |
|
7 |
* are met: |
|
8 |
* 1. Redistributions of source code must retain the above copyright |
|
9 |
* notice, this list of conditions and the following disclaimer. |
|
10 |
* 2. Redistributions in binary form must reproduce the above copyright |
|
11 |
* notice, this list of conditions and the following disclaimer in the |
|
12 |
* documentation and/or other materials provided with the distribution. |
|
13 |
* |
|
14 |
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
|
15 |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
16 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
17 |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
|
18 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
19 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
20 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
21 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
22 |
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
23 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
24 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
25 |
*/ |
|
26 |
||
27 |
#include "config.h" |
|
28 |
#include "PluginDatabase.h" |
|
29 |
||
30 |
#include "Frame.h" |
|
31 |
#include "KURL.h" |
|
32 |
#include "PluginDatabaseClient.h" |
|
33 |
#include "PluginPackage.h" |
|
34 |
#include <stdlib.h> |
|
35 |
||
36 |
namespace WebCore { |
|
37 |
||
38 |
typedef HashMap<String, RefPtr<PluginPackage> > PluginPackageByNameMap; |
|
39 |
||
40 |
PluginDatabase::PluginDatabase() |
|
41 |
: m_client(0) |
|
42 |
{ |
|
43 |
} |
|
44 |
||
45 |
PluginDatabase* PluginDatabase::installedPlugins(bool populate) |
|
46 |
{ |
|
47 |
static PluginDatabase* plugins = 0; |
|
48 |
||
49 |
if (!plugins) { |
|
50 |
plugins = new PluginDatabase; |
|
51 |
||
52 |
if (populate) { |
|
53 |
plugins->setPluginDirectories(PluginDatabase::defaultPluginDirectories()); |
|
54 |
plugins->refresh(); |
|
55 |
} |
|
56 |
} |
|
57 |
||
58 |
return plugins; |
|
59 |
} |
|
60 |
||
61 |
bool PluginDatabase::isMIMETypeRegistered(const String& mimeType) |
|
62 |
{ |
|
63 |
if (mimeType.isNull()) |
|
64 |
return false; |
|
65 |
if (m_registeredMIMETypes.contains(mimeType)) |
|
66 |
return true; |
|
67 |
// No plugin was found, try refreshing the database and searching again |
|
68 |
return (refresh() && m_registeredMIMETypes.contains(mimeType)); |
|
69 |
} |
|
70 |
||
71 |
void PluginDatabase::addExtraPluginDirectory(const String& directory) |
|
72 |
{ |
|
73 |
m_pluginDirectories.append(directory); |
|
74 |
refresh(); |
|
75 |
} |
|
76 |
||
77 |
bool PluginDatabase::refresh() |
|
78 |
{ |
|
79 |
bool pluginSetChanged = false; |
|
80 |
||
81 |
if (!m_plugins.isEmpty()) { |
|
82 |
PluginSet pluginsToUnload; |
|
83 |
getDeletedPlugins(pluginsToUnload); |
|
84 |
||
85 |
// Unload plugins |
|
86 |
PluginSet::const_iterator end = pluginsToUnload.end(); |
|
87 |
for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it) |
|
88 |
remove(it->get()); |
|
89 |
||
90 |
pluginSetChanged = !pluginsToUnload.isEmpty(); |
|
91 |
} |
|
92 |
||
93 |
HashSet<String> paths; |
|
94 |
getPluginPathsInDirectories(paths); |
|
95 |
||
96 |
HashMap<String, time_t> pathsWithTimes; |
|
97 |
||
98 |
// We should only skip unchanged files if we didn't remove any plugins above. If we did remove |
|
99 |
// any plugins, we need to look at every plugin file so that, e.g., if the user has two versions |
|
100 |
// of RealPlayer installed and just removed the newer one, we'll pick up the older one. |
|
101 |
bool shouldSkipUnchangedFiles = !pluginSetChanged; |
|
102 |
||
103 |
HashSet<String>::const_iterator pathsEnd = paths.end(); |
|
104 |
for (HashSet<String>::const_iterator it = paths.begin(); it != pathsEnd; ++it) { |
|
105 |
time_t lastModified; |
|
106 |
if (!getFileModificationTime(*it, lastModified)) |
|
107 |
continue; |
|
108 |
||
109 |
pathsWithTimes.add(*it, lastModified); |
|
110 |
||
111 |
// If the path's timestamp hasn't changed since the last time we ran refresh(), we don't have to do anything. |
|
112 |
if (shouldSkipUnchangedFiles && m_pluginPathsWithTimes.get(*it) == lastModified) |
|
113 |
continue; |
|
114 |
||
115 |
if (RefPtr<PluginPackage> oldPackage = m_pluginsByPath.get(*it)) { |
|
116 |
ASSERT(!shouldSkipUnchangedFiles || oldPackage->lastModified() != lastModified); |
|
117 |
remove(oldPackage.get()); |
|
118 |
} |
|
119 |
||
120 |
if (!m_client || m_client->shouldLoadPluginAtPath(*it)) { |
|
121 |
RefPtr<PluginPackage> package = PluginPackage::createPackage(*it, lastModified); |
|
122 |
if (package && (!m_client || m_client->shouldLoadPluginPackage(package.get())) && add(package.release())) |
|
123 |
pluginSetChanged = true; |
|
124 |
} |
|
125 |
} |
|
126 |
||
127 |
// Cache all the paths we found with their timestamps for next time. |
|
128 |
pathsWithTimes.swap(m_pluginPathsWithTimes); |
|
129 |
||
130 |
if (!pluginSetChanged) |
|
131 |
return false; |
|
132 |
||
133 |
m_registeredMIMETypes.clear(); |
|
134 |
||
135 |
// Register plug-in MIME types |
|
136 |
PluginSet::const_iterator end = m_plugins.end(); |
|
137 |
for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
|
138 |
// Get MIME types |
|
139 |
MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); |
|
140 |
MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end(); |
|
141 |
for (; map_it != map_end; ++map_it) |
|
142 |
m_registeredMIMETypes.add(map_it->first); |
|
143 |
} |
|
144 |
||
145 |
return true; |
|
146 |
} |
|
147 |
||
148 |
Vector<PluginPackage*> PluginDatabase::plugins() const |
|
149 |
{ |
|
150 |
Vector<PluginPackage*> result; |
|
151 |
||
152 |
PluginSet::const_iterator end = m_plugins.end(); |
|
153 |
for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) |
|
154 |
result.append((*it).get()); |
|
155 |
||
156 |
return result; |
|
157 |
} |
|
158 |
||
159 |
int PluginDatabase::preferredPluginCompare(const void* a, const void* b) |
|
160 |
{ |
|
161 |
PluginPackage* pluginA = *static_cast<PluginPackage* const*>(a); |
|
162 |
PluginPackage* pluginB = *static_cast<PluginPackage* const*>(b); |
|
163 |
||
164 |
return pluginA->compare(*pluginB); |
|
165 |
} |
|
166 |
||
167 |
PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType) |
|
168 |
{ |
|
169 |
if (mimeType.isEmpty()) |
|
170 |
return 0; |
|
171 |
||
172 |
String key = mimeType.lower(); |
|
173 |
PluginSet::const_iterator end = m_plugins.end(); |
|
174 |
PluginPackage* preferredPlugin = m_preferredPlugins.get(key).get(); |
|
175 |
if (preferredPlugin |
|
176 |
&& preferredPlugin->isEnabled() |
|
177 |
&& preferredPlugin->mimeToDescriptions().contains(key)) { |
|
178 |
return preferredPlugin; |
|
179 |
} |
|
180 |
||
181 |
Vector<PluginPackage*, 2> pluginChoices; |
|
182 |
||
183 |
for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
|
184 |
PluginPackage* plugin = (*it).get(); |
|
185 |
||
186 |
if (!plugin->isEnabled()) |
|
187 |
continue; |
|
188 |
||
189 |
if (plugin->mimeToDescriptions().contains(key)) |
|
190 |
pluginChoices.append(plugin); |
|
191 |
} |
|
192 |
||
193 |
if (pluginChoices.isEmpty()) |
|
194 |
return 0; |
|
195 |
||
196 |
qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); |
|
197 |
||
198 |
return pluginChoices[0]; |
|
199 |
} |
|
200 |
||
201 |
String PluginDatabase::MIMETypeForExtension(const String& extension) const |
|
202 |
{ |
|
203 |
if (extension.isEmpty()) |
|
204 |
return String(); |
|
205 |
||
206 |
PluginSet::const_iterator end = m_plugins.end(); |
|
207 |
String mimeType; |
|
208 |
Vector<PluginPackage*, 2> pluginChoices; |
|
209 |
HashMap<PluginPackage*, String> mimeTypeForPlugin; |
|
210 |
||
211 |
for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
|
212 |
if (!(*it)->isEnabled()) |
|
213 |
continue; |
|
214 |
||
215 |
MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end(); |
|
216 |
||
217 |
for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) { |
|
218 |
mimeType = mime_it->first; |
|
219 |
PluginPackage* preferredPlugin = m_preferredPlugins.get(mimeType).get(); |
|
220 |
const Vector<String>& extensions = mime_it->second; |
|
221 |
bool foundMapping = false; |
|
222 |
for (unsigned i = 0; i < extensions.size(); i++) { |
|
223 |
if (equalIgnoringCase(extensions[i], extension)) { |
|
224 |
PluginPackage* plugin = (*it).get(); |
|
225 |
||
226 |
if (preferredPlugin && PluginPackage::equal(*plugin, *preferredPlugin)) |
|
227 |
return mimeType; |
|
228 |
||
229 |
pluginChoices.append(plugin); |
|
230 |
mimeTypeForPlugin.add(plugin, mimeType); |
|
231 |
foundMapping = true; |
|
232 |
break; |
|
233 |
} |
|
234 |
} |
|
235 |
if (foundMapping) |
|
236 |
break; |
|
237 |
} |
|
238 |
} |
|
239 |
||
240 |
if (pluginChoices.isEmpty()) |
|
241 |
return String(); |
|
242 |
||
243 |
qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); |
|
244 |
||
245 |
return mimeTypeForPlugin.get(pluginChoices[0]); |
|
246 |
} |
|
247 |
||
248 |
PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType) |
|
249 |
{ |
|
250 |
PluginPackage* plugin = pluginForMIMEType(mimeType); |
|
251 |
String filename = url.string(); |
|
252 |
||
253 |
if (!plugin) { |
|
254 |
String filename = url.lastPathComponent(); |
|
255 |
if (!filename.endsWith("/")) { |
|
256 |
int extensionPos = filename.reverseFind('.'); |
|
257 |
if (extensionPos != -1) { |
|
258 |
String extension = filename.substring(extensionPos + 1); |
|
259 |
||
260 |
mimeType = MIMETypeForExtension(extension); |
|
261 |
plugin = pluginForMIMEType(mimeType); |
|
262 |
} |
|
263 |
} |
|
264 |
} |
|
265 |
||
266 |
// FIXME: if no plugin could be found, query Windows for the mime type |
|
267 |
// corresponding to the extension. |
|
268 |
||
269 |
return plugin; |
|
270 |
} |
|
271 |
||
272 |
void PluginDatabase::setPreferredPluginForMIMEType(const String& mimeType, PluginPackage* plugin) |
|
273 |
{ |
|
274 |
if (!plugin || plugin->mimeToExtensions().contains(mimeType)) |
|
275 |
m_preferredPlugins.set(mimeType.lower(), plugin); |
|
276 |
} |
|
277 |
||
278 |
void PluginDatabase::getDeletedPlugins(PluginSet& plugins) const |
|
279 |
{ |
|
280 |
PluginSet::const_iterator end = m_plugins.end(); |
|
281 |
for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
|
282 |
if (!fileExists((*it)->path())) |
|
283 |
plugins.add(*it); |
|
284 |
} |
|
285 |
} |
|
286 |
||
287 |
bool PluginDatabase::add(PassRefPtr<PluginPackage> prpPackage) |
|
288 |
{ |
|
289 |
ASSERT_ARG(prpPackage, prpPackage); |
|
290 |
||
291 |
RefPtr<PluginPackage> package = prpPackage; |
|
292 |
||
293 |
if (!m_plugins.add(package).second) |
|
294 |
return false; |
|
295 |
||
296 |
m_pluginsByPath.add(package->path(), package); |
|
297 |
return true; |
|
298 |
} |
|
299 |
||
300 |
void PluginDatabase::remove(PluginPackage* package) |
|
301 |
{ |
|
302 |
MIMEToExtensionsMap::const_iterator it = package->mimeToExtensions().begin(); |
|
303 |
MIMEToExtensionsMap::const_iterator end = package->mimeToExtensions().end(); |
|
304 |
for ( ; it != end; ++it) { |
|
305 |
PluginPackageByNameMap::iterator packageInMap = m_preferredPlugins.find(it->first); |
|
306 |
if (packageInMap != m_preferredPlugins.end() && packageInMap->second == package) |
|
307 |
m_preferredPlugins.remove(packageInMap); |
|
308 |
} |
|
309 |
||
310 |
m_plugins.remove(package); |
|
311 |
m_pluginsByPath.remove(package->path()); |
|
312 |
} |
|
313 |
||
314 |
void PluginDatabase::clear() |
|
315 |
{ |
|
316 |
m_plugins.clear(); |
|
317 |
m_pluginsByPath.clear(); |
|
318 |
m_pluginPathsWithTimes.clear(); |
|
319 |
m_registeredMIMETypes.clear(); |
|
320 |
m_preferredPlugins.clear(); |
|
321 |
} |
|
322 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
323 |
#if (!PLATFORM(WINCE)) && (!PLATFORM(SYMBIAN)) && (!PLATFORM(WIN_OS) || PLATFORM(WX) || !ENABLE(NETSCAPE_PLUGIN_API)) |
0 | 324 |
// For Safari/Win the following three methods are implemented |
325 |
// in PluginDatabaseWin.cpp, but if we can use WebCore constructs |
|
326 |
// for the logic we should perhaps move it here under XP_WIN? |
|
327 |
||
328 |
Vector<String> PluginDatabase::defaultPluginDirectories() |
|
329 |
{ |
|
330 |
Vector<String> paths; |
|
331 |
||
332 |
// Add paths specific to each platform |
|
333 |
#if defined(XP_UNIX) |
|
334 |
String userPluginPath = homeDirectoryPath(); |
|
335 |
userPluginPath.append(String("/.mozilla/plugins")); |
|
336 |
paths.append(userPluginPath); |
|
337 |
||
338 |
userPluginPath = homeDirectoryPath(); |
|
339 |
userPluginPath.append(String("/.netscape/plugins")); |
|
340 |
paths.append(userPluginPath); |
|
341 |
||
342 |
paths.append("/usr/lib/browser/plugins"); |
|
343 |
paths.append("/usr/local/lib/mozilla/plugins"); |
|
344 |
paths.append("/usr/lib/firefox/plugins"); |
|
345 |
paths.append("/usr/lib64/browser-plugins"); |
|
346 |
paths.append("/usr/lib/browser-plugins"); |
|
347 |
paths.append("/usr/lib/mozilla/plugins"); |
|
348 |
paths.append("/usr/local/netscape/plugins"); |
|
349 |
paths.append("/opt/mozilla/plugins"); |
|
350 |
paths.append("/opt/mozilla/lib/plugins"); |
|
351 |
paths.append("/opt/netscape/plugins"); |
|
352 |
paths.append("/opt/netscape/communicator/plugins"); |
|
353 |
paths.append("/usr/lib/netscape/plugins"); |
|
354 |
paths.append("/usr/lib/netscape/plugins-libc5"); |
|
355 |
paths.append("/usr/lib/netscape/plugins-libc6"); |
|
356 |
paths.append("/usr/lib64/netscape/plugins"); |
|
357 |
paths.append("/usr/lib64/mozilla/plugins"); |
|
358 |
paths.append("/usr/lib/nsbrowser/plugins"); |
|
359 |
paths.append("/usr/lib64/nsbrowser/plugins"); |
|
360 |
||
361 |
String mozHome(getenv("MOZILLA_HOME")); |
|
362 |
mozHome.append("/plugins"); |
|
363 |
paths.append(mozHome); |
|
364 |
||
365 |
Vector<String> mozPaths; |
|
366 |
String mozPath(getenv("MOZ_PLUGIN_PATH")); |
|
367 |
mozPath.split(UChar(':'), /* allowEmptyEntries */ false, mozPaths); |
|
368 |
paths.append(mozPaths); |
|
369 |
#elif defined(XP_MACOSX) |
|
370 |
String userPluginPath = homeDirectoryPath(); |
|
371 |
userPluginPath.append(String("/Library/Internet Plug-Ins")); |
|
372 |
paths.append(userPluginPath); |
|
373 |
paths.append("/Library/Internet Plug-Ins"); |
|
374 |
#elif defined(XP_WIN) |
|
375 |
String userPluginPath = homeDirectoryPath(); |
|
376 |
userPluginPath.append(String("\\Application Data\\Mozilla\\plugins")); |
|
377 |
paths.append(userPluginPath); |
|
378 |
#endif |
|
379 |
||
380 |
// Add paths specific to each port |
|
381 |
#if PLATFORM(QT) |
|
382 |
Vector<String> qtPaths; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
383 |
String qtPath(qgetenv("QTWEBKIT_PLUGIN_PATH").constData()); |
0 | 384 |
qtPath.split(UChar(':'), /* allowEmptyEntries */ false, qtPaths); |
385 |
paths.append(qtPaths); |
|
386 |
#endif |
|
387 |
||
388 |
return paths; |
|
389 |
} |
|
390 |
||
391 |
bool PluginDatabase::isPreferredPluginDirectory(const String& path) |
|
392 |
{ |
|
393 |
String preferredPath = homeDirectoryPath(); |
|
394 |
||
395 |
#if defined(XP_UNIX) |
|
396 |
preferredPath.append(String("/.mozilla/plugins")); |
|
397 |
#elif defined(XP_MACOSX) |
|
398 |
preferredPath.append(String("/Library/Internet Plug-Ins")); |
|
399 |
#elif defined(XP_WIN) |
|
400 |
preferredPath.append(String("\\Application Data\\Mozilla\\plugins")); |
|
401 |
#endif |
|
402 |
||
403 |
// TODO: We should normalize the path before doing a comparison. |
|
404 |
return path == preferredPath; |
|
405 |
} |
|
406 |
||
407 |
void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const |
|
408 |
{ |
|
409 |
// FIXME: This should be a case insensitive set. |
|
410 |
HashSet<String> uniqueFilenames; |
|
411 |
||
412 |
#if defined(XP_UNIX) |
|
413 |
String fileNameFilter("*.so"); |
|
414 |
#else |
|
415 |
String fileNameFilter(""); |
|
416 |
#endif |
|
417 |
||
418 |
Vector<String>::const_iterator dirsEnd = m_pluginDirectories.end(); |
|
419 |
for (Vector<String>::const_iterator dIt = m_pluginDirectories.begin(); dIt != dirsEnd; ++dIt) { |
|
420 |
Vector<String> pluginPaths = listDirectory(*dIt, fileNameFilter); |
|
421 |
Vector<String>::const_iterator pluginsEnd = pluginPaths.end(); |
|
422 |
for (Vector<String>::const_iterator pIt = pluginPaths.begin(); pIt != pluginsEnd; ++pIt) { |
|
423 |
if (!fileExists(*pIt)) |
|
424 |
continue; |
|
425 |
||
426 |
paths.add(*pIt); |
|
427 |
} |
|
428 |
} |
|
429 |
} |
|
430 |
||
431 |
#endif // !PLATFORM(SYMBIAN) && !PLATFORM(WIN_OS) |
|
432 |
||
433 |
} |