dba5ef9c15c6b19b12e935c41d1f93836939380a
[WebKit-https.git] / WebCore / plugins / PluginDatabase.cpp
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 "PluginPackage.h"
33 #include <stdlib.h>
34
35 namespace WebCore {
36
37 PluginDatabase* PluginDatabase::installedPlugins()
38 {
39     static PluginDatabase* plugins = 0;
40     
41     if (!plugins) {
42         plugins = new PluginDatabase;
43         plugins->setPluginPaths(PluginDatabase::defaultPluginPaths());
44         plugins->refresh();
45     }
46
47     return plugins;
48 }
49
50 bool PluginDatabase::isMIMETypeRegistered(const String& mimeType)
51 {
52     if (mimeType.isNull())
53         return false;
54     if (m_registeredMIMETypes.contains(mimeType))
55         return true;
56     // No plugin was found, try refreshing the database and searching again
57     return (refresh() && m_registeredMIMETypes.contains(mimeType));
58 }
59
60 void PluginDatabase::addExtraPluginPath(const String& path)
61 {
62     m_pluginPaths.append(path);
63     refresh();
64 }
65
66 bool PluginDatabase::refresh()
67 {   
68     PluginSet newPlugins;
69
70     bool pluginSetChanged = false;
71
72     // Create a new set of plugins
73     newPlugins = getPluginsInPaths();
74
75     if (!m_plugins.isEmpty()) {
76         m_registeredMIMETypes.clear();
77
78         PluginSet pluginsToUnload = m_plugins;
79
80         PluginSet::const_iterator end = newPlugins.end();
81         for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it)
82             pluginsToUnload.remove(*it);
83
84         end = m_plugins.end();
85         for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it)
86             newPlugins.remove(*it);
87
88         // Unload plugins
89         end = pluginsToUnload.end();
90         for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it)
91             m_plugins.remove(*it);
92
93         // Add new plugins
94         end = newPlugins.end();
95         for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it)
96             m_plugins.add(*it);
97
98         pluginSetChanged = !pluginsToUnload.isEmpty() || !newPlugins.isEmpty();
99     } else {
100         m_plugins = newPlugins;
101         PluginSet::const_iterator end = newPlugins.end();
102         for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it)
103             m_plugins.add(*it);
104
105         pluginSetChanged = !newPlugins.isEmpty();
106     }
107
108     // Register plug-in MIME types
109     PluginSet::const_iterator end = m_plugins.end();
110     for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
111         // Get MIME types
112         MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end();
113         for (MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); map_it != map_end; ++map_it) {
114             m_registeredMIMETypes.add(map_it->first);
115         }
116     }
117
118     return pluginSetChanged;
119 }
120
121 Vector<PluginPackage*> PluginDatabase::plugins() const
122 {
123     Vector<PluginPackage*> result;
124
125     PluginSet::const_iterator end = m_plugins.end();
126     for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it)
127         result.append((*it).get());
128
129     return result;
130 }
131
132 int PluginDatabase::preferredPluginCompare(const void* a, const void* b)
133 {
134     PluginPackage* pluginA = *static_cast<PluginPackage* const*>(a);
135     PluginPackage* pluginB = *static_cast<PluginPackage* const*>(b);
136
137     return pluginA->compare(*pluginB);
138 }
139
140 PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType)
141 {
142     if (mimeType.isEmpty())
143         return 0;
144
145     String key = mimeType.lower();
146     PluginSet::const_iterator end = m_plugins.end();
147
148     Vector<PluginPackage*, 2> pluginChoices;
149
150     for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
151         if ((*it)->mimeToDescriptions().contains(key))
152             pluginChoices.append((*it).get());
153     }
154
155     if (pluginChoices.isEmpty())
156         return 0;
157
158     qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare);
159
160     return pluginChoices[0];
161 }
162
163 String PluginDatabase::MIMETypeForExtension(const String& extension) const
164 {
165     if (extension.isEmpty())
166         return String();
167
168     PluginSet::const_iterator end = m_plugins.end();
169     String mimeType;
170     Vector<PluginPackage*, 2> pluginChoices;
171     HashMap<PluginPackage*, String> mimeTypeForPlugin;
172
173     for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
174         MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end();
175
176         for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) {
177             const Vector<String>& extensions = mime_it->second;
178             bool foundMapping = false;
179             for (unsigned i = 0; i < extensions.size(); i++) {
180                 if (equalIgnoringCase(extensions[i], extension)) {
181                     PluginPackage* plugin = (*it).get();
182                     pluginChoices.append(plugin);
183                     mimeTypeForPlugin.add(plugin, mime_it->first);
184                     foundMapping = true;
185                     break;
186                 }
187             }
188             if (foundMapping)
189                 break;
190         }
191     }
192
193     if (pluginChoices.isEmpty())
194         return String();
195
196     qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare);
197
198     return mimeTypeForPlugin.get(pluginChoices[0]);
199 }
200
201 PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType)
202 {
203     PluginPackage* plugin = pluginForMIMEType(mimeType);
204     String filename = url.string();
205     
206     if (!plugin) {
207         String filename = url.lastPathComponent();
208         if (!filename.endsWith("/")) {
209             int extensionPos = filename.reverseFind('.');
210             if (extensionPos != -1) {
211                 String extension = filename.substring(extensionPos + 1);
212
213                 mimeType = MIMETypeForExtension(extension);
214                 plugin = pluginForMIMEType(mimeType);
215             }
216         }
217     }
218
219     // FIXME: if no plugin could be found, query Windows for the mime type 
220     // corresponding to the extension.
221
222     return plugin;
223 }
224
225 }