initial import
[vuplus_webkit] / Source / WebKit2 / UIProcess / Plugins / PluginInfoStore.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "PluginInfoStore.h"
28
29 #include "PluginModuleInfo.h"
30 #include <WebCore/KURL.h>
31 #include <WebCore/MIMETypeRegistry.h>
32 #include <algorithm>
33 #include <wtf/ListHashSet.h>
34 #include <wtf/StdLibExtras.h>
35
36 using namespace std;
37 using namespace WebCore;
38
39 namespace WebKit {
40
41 PluginInfoStore::PluginInfoStore()
42     : m_pluginListIsUpToDate(false)
43 {
44 }
45
46 void PluginInfoStore::setAdditionalPluginsDirectories(const Vector<String>& directories)
47 {
48     m_additionalPluginsDirectories = directories;
49     refresh();
50 }
51
52 void PluginInfoStore::refresh()
53 {
54     m_pluginListIsUpToDate = false;
55 }
56
57 template <typename T, typename U>
58 static void addFromVector(T& hashSet, const U& vector)
59 {
60     for (size_t i = 0; i < vector.size(); ++i)
61         hashSet.add(vector[i]);
62 }
63
64 // We use a ListHashSet so that plugins will be loaded from the additional plugins directories first
65 // (which in turn means those plugins will be preferred if two plugins claim the same MIME type).
66 #if OS(WINDOWS)
67 typedef ListHashSet<String, 32, CaseFoldingHash> PathHashSet;
68 #else
69 typedef ListHashSet<String, 32> PathHashSet;
70 #endif
71
72 void PluginInfoStore::loadPluginsIfNecessary()
73 {
74     if (m_pluginListIsUpToDate)
75         return;
76
77     PathHashSet uniquePluginPaths;
78
79     // First, load plug-ins from the additional plug-ins directories specified.
80     for (size_t i = 0; i < m_additionalPluginsDirectories.size(); ++i)
81         addFromVector(uniquePluginPaths, pluginPathsInDirectory(m_additionalPluginsDirectories[i]));
82
83     // Then load plug-ins from the standard plug-ins directories.
84     Vector<String> directories = pluginsDirectories();
85     for (size_t i = 0; i < directories.size(); ++i)
86         addFromVector(uniquePluginPaths, pluginPathsInDirectory(directories[i]));
87
88     // Then load plug-ins that are not in the standard plug-ins directories.
89     addFromVector(uniquePluginPaths, individualPluginPaths());
90
91     Vector<PluginModuleInfo> plugins;
92
93     PathHashSet::const_iterator end = uniquePluginPaths.end();
94     for (PathHashSet::const_iterator it = uniquePluginPaths.begin(); it != end; ++it)
95         loadPlugin(plugins, *it);
96
97     m_plugins.swap(plugins);
98     m_pluginListIsUpToDate = true;
99 }
100
101 void PluginInfoStore::loadPlugin(Vector<PluginModuleInfo>& plugins, const String& pluginPath)
102 {
103     PluginModuleInfo plugin;
104     
105     if (!getPluginInfo(pluginPath, plugin))
106         return;
107
108     if (!shouldUsePlugin(plugins, plugin))
109         return;
110     
111     plugins.append(plugin);
112 }
113
114 Vector<PluginModuleInfo> PluginInfoStore::plugins()
115 {
116     loadPluginsIfNecessary();
117
118     Vector<PluginModuleInfo> plugins(m_plugins);
119
120     return plugins;
121 }
122
123 PluginModuleInfo PluginInfoStore::findPluginForMIMEType(const String& mimeType) const
124 {
125     ASSERT(!mimeType.isNull());
126     
127     for (size_t i = 0; i < m_plugins.size(); ++i) {
128         const PluginModuleInfo& plugin = m_plugins[i];
129         
130         for (size_t j = 0; j < plugin.info.mimes.size(); ++j) {
131             const MimeClassInfo& mimeClassInfo = plugin.info.mimes[j];
132             if (mimeClassInfo.type == mimeType)
133                 return plugin;
134         }
135     }
136     
137     return PluginModuleInfo();
138 }
139
140 PluginModuleInfo PluginInfoStore::findPluginForExtension(const String& extension, String& mimeType) const
141 {
142     ASSERT(!extension.isNull());
143     
144     for (size_t i = 0; i < m_plugins.size(); ++i) {
145         const PluginModuleInfo& plugin = m_plugins[i];
146         
147         for (size_t j = 0; j < plugin.info.mimes.size(); ++j) {
148             const MimeClassInfo& mimeClassInfo = plugin.info.mimes[j];
149             
150             const Vector<String>& extensions = mimeClassInfo.extensions;
151             
152             if (find(extensions.begin(), extensions.end(), extension) != extensions.end()) {
153                 // We found a supported extension, set the correct MIME type.
154                 mimeType = mimeClassInfo.type;
155                 return plugin;
156             }
157         }
158     }
159     
160     return PluginModuleInfo();
161 }
162
163 static inline String pathExtension(const KURL& url)
164 {
165     String extension;
166     String filename = url.lastPathComponent();
167     if (!filename.endsWith("/")) {
168         int extensionPos = filename.reverseFind('.');
169         if (extensionPos != -1)
170             extension = filename.substring(extensionPos + 1);
171     }
172     
173     return extension;
174 }
175
176 #if !PLATFORM(MAC)
177 String PluginInfoStore::getMIMETypeForExtension(const String& extension)
178 {
179     return MIMETypeRegistry::getMIMETypeForExtension(extension);
180 }
181 #endif
182
183 PluginModuleInfo PluginInfoStore::findPlugin(String& mimeType, const KURL& url)
184 {
185     loadPluginsIfNecessary();
186     
187     // First, check if we can get the plug-in based on its MIME type.
188     if (!mimeType.isNull()) {
189         PluginModuleInfo plugin = findPluginForMIMEType(mimeType);
190         if (!plugin.path.isNull())
191             return plugin;
192     }
193
194     // Next, check if any plug-ins claim to support the URL extension.
195     String extension = pathExtension(url).lower();
196     if (!extension.isNull() && mimeType.isEmpty()) {
197         PluginModuleInfo plugin = findPluginForExtension(extension, mimeType);
198         if (!plugin.path.isNull())
199             return plugin;
200         
201         // Finally, try to get the MIME type from the extension in a platform specific manner and use that.
202         String extensionMimeType = getMIMETypeForExtension(extension);
203         if (!extensionMimeType.isNull()) {
204             PluginModuleInfo plugin = findPluginForMIMEType(extensionMimeType);
205             if (!plugin.path.isNull()) {
206                 mimeType = extensionMimeType;
207                 return plugin;
208             }
209         }
210     }
211     
212     return PluginModuleInfo();
213 }
214
215 PluginModuleInfo PluginInfoStore::infoForPluginWithPath(const String& pluginPath) const
216 {
217     for (size_t i = 0; i < m_plugins.size(); ++i) {
218         if (m_plugins[i].path == pluginPath)
219             return m_plugins[i];
220     }
221     
222     ASSERT_NOT_REACHED();
223     return PluginModuleInfo();
224 }
225
226 } // namespace WebKit