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 <windows.h>
34 #include <shlwapi.h>
35
36 #if COMPILER(MINGW)
37 #define _countof(x) (sizeof(x)/sizeof(x[0]))
38 #endif
39
40 namespace WebCore {
41
addPluginPathsFromRegistry(HKEY rootKey,HashSet<String> & paths)42 static inline void addPluginPathsFromRegistry(HKEY rootKey, HashSet<String>& paths)
43 {
44 HKEY key;
45 HRESULT result = RegOpenKeyExW(rootKey, L"Software\\MozillaPlugins", 0, KEY_ENUMERATE_SUB_KEYS, &key);
46
47 if (result != ERROR_SUCCESS)
48 return;
49
50 wchar_t name[128];
51 FILETIME lastModified;
52
53 // Enumerate subkeys
54 for (int i = 0;; i++) {
55 DWORD nameLen = _countof(name);
56 result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
57
58 if (result != ERROR_SUCCESS)
59 break;
60
61 WCHAR pathStr[_MAX_PATH];
62 DWORD pathStrSize = sizeof(pathStr);
63 DWORD type;
64
65 result = SHGetValue(key, name, TEXT("Path"), &type, (LPBYTE)pathStr, &pathStrSize);
66 if (result != ERROR_SUCCESS || type != REG_SZ)
67 continue;
68
69 paths.add(String(pathStr, pathStrSize / sizeof(WCHAR) - 1));
70 }
71
72 RegCloseKey(key);
73 }
74
getPluginPathsInDirectories(HashSet<String> & paths) const75 void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
76 {
77 // FIXME: This should be a case insensitive set.
78 HashSet<String> uniqueFilenames;
79
80 HANDLE hFind = INVALID_HANDLE_VALUE;
81 WIN32_FIND_DATAW findFileData;
82
83 String oldWMPPluginPath;
84 String newWMPPluginPath;
85
86 Vector<String>::const_iterator end = m_pluginDirectories.end();
87 for (Vector<String>::const_iterator it = m_pluginDirectories.begin(); it != end; ++it) {
88 String pattern = *it + "\\*";
89
90 hFind = FindFirstFileW(pattern.charactersWithNullTermination(), &findFileData);
91
92 if (hFind == INVALID_HANDLE_VALUE)
93 continue;
94
95 do {
96 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
97 continue;
98
99 String filename = String(findFileData.cFileName, wcslen(findFileData.cFileName));
100 if ((!filename.startsWith("np", false) || !filename.endsWith("dll", false)) &&
101 (!equalIgnoringCase(filename, "Plugin.dll") || !it->endsWith("Shockwave 10", false)))
102 continue;
103
104 String fullPath = *it + "\\" + filename;
105 if (!uniqueFilenames.add(fullPath).second)
106 continue;
107
108 paths.add(fullPath);
109
110 if (equalIgnoringCase(filename, "npdsplay.dll"))
111 oldWMPPluginPath = fullPath;
112 else if (equalIgnoringCase(filename, "np-mswmp.dll"))
113 newWMPPluginPath = fullPath;
114
115 } while (FindNextFileW(hFind, &findFileData) != 0);
116
117 FindClose(hFind);
118 }
119
120 addPluginPathsFromRegistry(HKEY_LOCAL_MACHINE, paths);
121 addPluginPathsFromRegistry(HKEY_CURRENT_USER, paths);
122
123 // If both the old and new WMP plugin are present in the plugins set,
124 // we remove the old one so we don't end up choosing the old one.
125 if (!oldWMPPluginPath.isEmpty() && !newWMPPluginPath.isEmpty())
126 paths.remove(oldWMPPluginPath);
127 }
128
parseVersionString(const String & versionString)129 static inline Vector<int> parseVersionString(const String& versionString)
130 {
131 Vector<int> version;
132
133 unsigned startPos = 0;
134 unsigned endPos;
135
136 while (startPos < versionString.length()) {
137 for (endPos = startPos; endPos < versionString.length(); ++endPos)
138 if (versionString[endPos] == '.' || versionString[endPos] == '_')
139 break;
140
141 int versionComponent = versionString.substring(startPos, endPos - startPos).toInt();
142 version.append(versionComponent);
143
144 startPos = endPos + 1;
145 }
146
147 return version;
148 }
149
150 // This returns whether versionA is higher than versionB
compareVersions(const Vector<int> & versionA,const Vector<int> & versionB)151 static inline bool compareVersions(const Vector<int>& versionA, const Vector<int>& versionB)
152 {
153 for (unsigned i = 0; i < versionA.size(); i++) {
154 if (i >= versionB.size())
155 return true;
156
157 if (versionA[i] > versionB[i])
158 return true;
159 else if (versionA[i] < versionB[i])
160 return false;
161 }
162
163 // If we come here, the versions are either the same or versionB has an extra component, just return false
164 return false;
165 }
166
addMozillaPluginDirectories(Vector<String> & directories)167 static inline void addMozillaPluginDirectories(Vector<String>& directories)
168 {
169 // Enumerate all Mozilla plugin directories in the registry
170 HKEY key;
171 LONG result;
172
173 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Mozilla"), 0, KEY_READ, &key);
174 if (result == ERROR_SUCCESS) {
175 WCHAR name[128];
176 FILETIME lastModified;
177
178 // Enumerate subkeys
179 for (int i = 0;; i++) {
180 DWORD nameLen = sizeof(name) / sizeof(WCHAR);
181 result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
182
183 if (result != ERROR_SUCCESS)
184 break;
185
186 String extensionsPath = String(name, nameLen) + "\\Extensions";
187 HKEY extensionsKey;
188
189 // Try opening the key
190 result = RegOpenKeyEx(key, extensionsPath.charactersWithNullTermination(), 0, KEY_READ, &extensionsKey);
191
192 if (result == ERROR_SUCCESS) {
193 // Now get the plugins directory
194 WCHAR pluginsDirectoryStr[_MAX_PATH];
195 DWORD pluginsDirectorySize = sizeof(pluginsDirectoryStr);
196 DWORD type;
197
198 result = RegQueryValueEx(extensionsKey, TEXT("Plugins"), 0, &type, (LPBYTE)&pluginsDirectoryStr, &pluginsDirectorySize);
199
200 if (result == ERROR_SUCCESS && type == REG_SZ)
201 directories.append(String(pluginsDirectoryStr, pluginsDirectorySize / sizeof(WCHAR) - 1));
202
203 RegCloseKey(extensionsKey);
204 }
205 }
206
207 RegCloseKey(key);
208 }
209 }
210
addWindowsMediaPlayerPluginDirectory(Vector<String> & directories)211 static inline void addWindowsMediaPlayerPluginDirectory(Vector<String>& directories)
212 {
213 // The new WMP Firefox plugin is installed in \PFiles\Plugins if it can't find any Firefox installs
214 WCHAR pluginDirectoryStr[_MAX_PATH + 1];
215 DWORD pluginDirectorySize = ::ExpandEnvironmentStringsW(TEXT("%SYSTEMDRIVE%\\PFiles\\Plugins"), pluginDirectoryStr, _countof(pluginDirectoryStr));
216
217 if (pluginDirectorySize > 0 && pluginDirectorySize <= _countof(pluginDirectoryStr))
218 directories.append(String(pluginDirectoryStr, pluginDirectorySize - 1));
219
220 DWORD type;
221 WCHAR installationDirectoryStr[_MAX_PATH];
222 DWORD installationDirectorySize = sizeof(installationDirectoryStr);
223
224 HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\MediaPlayer"), TEXT("Installation Directory"), &type, (LPBYTE)&installationDirectoryStr, &installationDirectorySize);
225
226 if (result == ERROR_SUCCESS && type == REG_SZ)
227 directories.append(String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1));
228 }
229
addQuickTimePluginDirectory(Vector<String> & directories)230 static inline void addQuickTimePluginDirectory(Vector<String>& directories)
231 {
232 DWORD type;
233 WCHAR installationDirectoryStr[_MAX_PATH];
234 DWORD installationDirectorySize = sizeof(installationDirectoryStr);
235
236 HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Apple Computer, Inc.\\QuickTime"), TEXT("InstallDir"), &type, (LPBYTE)&installationDirectoryStr, &installationDirectorySize);
237
238 if (result == ERROR_SUCCESS && type == REG_SZ) {
239 String pluginDir = String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1) + "\\plugins";
240 directories.append(pluginDir);
241 }
242 }
243
addAdobeAcrobatPluginDirectory(Vector<String> & directories)244 static inline void addAdobeAcrobatPluginDirectory(Vector<String>& directories)
245 {
246 HKEY key;
247 HRESULT result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Adobe\\Acrobat Reader"), 0, KEY_READ, &key);
248 if (result != ERROR_SUCCESS)
249 return;
250
251 WCHAR name[128];
252 FILETIME lastModified;
253
254 Vector<int> latestAcrobatVersion;
255 String latestAcrobatVersionString;
256
257 // Enumerate subkeys
258 for (int i = 0;; i++) {
259 DWORD nameLen = sizeof(name) / sizeof(WCHAR);
260 result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
261
262 if (result != ERROR_SUCCESS)
263 break;
264
265 Vector<int> acrobatVersion = parseVersionString(String(name, nameLen));
266 if (compareVersions(acrobatVersion, latestAcrobatVersion)) {
267 latestAcrobatVersion = acrobatVersion;
268 latestAcrobatVersionString = String(name, nameLen);
269 }
270 }
271
272 if (!latestAcrobatVersionString.isNull()) {
273 DWORD type;
274 WCHAR acrobatInstallPathStr[_MAX_PATH];
275 DWORD acrobatInstallPathSize = sizeof(acrobatInstallPathStr);
276
277 String acrobatPluginKeyPath = "Software\\Adobe\\Acrobat Reader\\" + latestAcrobatVersionString + "\\InstallPath";
278 result = SHGetValue(HKEY_LOCAL_MACHINE, acrobatPluginKeyPath.charactersWithNullTermination(), 0, &type, (LPBYTE)acrobatInstallPathStr, &acrobatInstallPathSize);
279
280 if (result == ERROR_SUCCESS) {
281 String acrobatPluginDirectory = String(acrobatInstallPathStr, acrobatInstallPathSize / sizeof(WCHAR) - 1) + "\\browser";
282 directories.append(acrobatPluginDirectory);
283 }
284 }
285
286 RegCloseKey(key);
287 }
288
safariPluginsDirectory()289 static inline String safariPluginsDirectory()
290 {
291 WCHAR moduleFileNameStr[_MAX_PATH];
292 static String pluginsDirectory;
293 static bool cachedPluginDirectory = false;
294
295 if (!cachedPluginDirectory) {
296 cachedPluginDirectory = true;
297
298 int moduleFileNameLen = GetModuleFileName(0, moduleFileNameStr, _MAX_PATH);
299
300 if (!moduleFileNameLen || moduleFileNameLen == _MAX_PATH)
301 goto exit;
302
303 if (!PathRemoveFileSpec(moduleFileNameStr))
304 goto exit;
305
306 pluginsDirectory = String(moduleFileNameStr) + "\\Plugins";
307 }
308 exit:
309 return pluginsDirectory;
310 }
311
addMacromediaPluginDirectories(Vector<String> & directories)312 static inline void addMacromediaPluginDirectories(Vector<String>& directories)
313 {
314 WCHAR systemDirectoryStr[MAX_PATH];
315
316 if (GetSystemDirectory(systemDirectoryStr, _countof(systemDirectoryStr)) == 0)
317 return;
318
319 WCHAR macromediaDirectoryStr[MAX_PATH];
320
321 PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Flash"));
322 directories.append(macromediaDirectoryStr);
323
324 PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Shockwave 10"));
325 directories.append(macromediaDirectoryStr);
326 }
327
defaultPluginDirectories()328 Vector<String> PluginDatabase::defaultPluginDirectories()
329 {
330 Vector<String> directories;
331 String ourDirectory = safariPluginsDirectory();
332
333 if (!ourDirectory.isNull())
334 directories.append(ourDirectory);
335 addQuickTimePluginDirectory(directories);
336 addAdobeAcrobatPluginDirectory(directories);
337 addMozillaPluginDirectories(directories);
338 addWindowsMediaPlayerPluginDirectory(directories);
339 addMacromediaPluginDirectories(directories);
340
341 return directories;
342 }
343
isPreferredPluginDirectory(const String & directory)344 bool PluginDatabase::isPreferredPluginDirectory(const String& directory)
345 {
346 String ourDirectory = safariPluginsDirectory();
347
348 if (!ourDirectory.isNull() && !directory.isNull())
349 return ourDirectory == directory;
350
351 return false;
352 }
353
354 }
355