1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
4 * Copyright (C) 2008-2009 Torch Mobile, Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "config.h"
29 #include "PluginDatabase.h"
30
31 #include "Frame.h"
32 #include "KURL.h"
33 #include "PluginPackage.h"
34 #include <windows.h>
35 #include <shlwapi.h>
36
37 #if OS(WINCE)
38 // WINCE doesn't support Registry Key Access Rights. The parameter should always be 0
39 #ifndef KEY_ENUMERATE_SUB_KEYS
40 #define KEY_ENUMERATE_SUB_KEYS 0
41 #endif
42
SHGetValue(HKEY hkey,LPCWSTR pszSubKey,LPCWSTR pszValue,LPDWORD pdwType,LPVOID pvData,LPDWORD pcbData)43 DWORD SHGetValue(HKEY hkey, LPCWSTR pszSubKey, LPCWSTR pszValue, LPDWORD pdwType, LPVOID pvData, LPDWORD pcbData)
44 {
45 HKEY key;
46 if (RegOpenKeyEx(hkey, pszSubKey, 0, 0, &key) == ERROR_SUCCESS) {
47 DWORD result = RegQueryValueEx(key, pszValue, 0, pdwType, (LPBYTE)pvData, pcbData);
48 RegCloseKey(key);
49 return result;
50 }
51 return ERROR_INVALID_NAME;
52 }
53
PathRemoveFileSpec(LPWSTR moduleFileNameStr)54 BOOL PathRemoveFileSpec(LPWSTR moduleFileNameStr)
55 {
56 if (!*moduleFileNameStr)
57 return FALSE;
58
59 LPWSTR lastPos = 0;
60 LPWSTR curPos = moduleFileNameStr;
61 do {
62 if (*curPos == L'/' || *curPos == L'\\')
63 lastPos = curPos;
64 } while (*++curPos);
65
66 if (lastPos == curPos - 1)
67 return FALSE;
68
69 if (lastPos)
70 *lastPos = 0;
71 else {
72 moduleFileNameStr[0] = L'\\';
73 moduleFileNameStr[1] = 0;
74 }
75
76 return TRUE;
77 }
78 #endif
79
80 namespace WebCore {
81
addPluginPathsFromRegistry(HKEY rootKey,HashSet<String> & paths)82 static inline void addPluginPathsFromRegistry(HKEY rootKey, HashSet<String>& paths)
83 {
84 HKEY key;
85 HRESULT result = RegOpenKeyExW(rootKey, L"Software\\MozillaPlugins", 0, KEY_ENUMERATE_SUB_KEYS, &key);
86
87 if (result != ERROR_SUCCESS)
88 return;
89
90 wchar_t name[128];
91 FILETIME lastModified;
92
93 // Enumerate subkeys
94 for (int i = 0;; i++) {
95 DWORD nameLen = WTF_ARRAY_LENGTH(name);
96 result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
97
98 if (result != ERROR_SUCCESS)
99 break;
100
101 WCHAR pathStr[_MAX_PATH];
102 DWORD pathStrSize = sizeof(pathStr);
103 DWORD type;
104
105 result = SHGetValue(key, name, TEXT("Path"), &type, (LPBYTE)pathStr, &pathStrSize);
106 if (result != ERROR_SUCCESS || type != REG_SZ)
107 continue;
108
109 paths.add(String(pathStr, pathStrSize / sizeof(WCHAR) - 1));
110 }
111
112 RegCloseKey(key);
113 }
114
getPluginPathsInDirectories(HashSet<String> & paths) const115 void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
116 {
117 // FIXME: This should be a case insensitive set.
118 HashSet<String> uniqueFilenames;
119
120 HANDLE hFind = INVALID_HANDLE_VALUE;
121 WIN32_FIND_DATAW findFileData;
122
123 String oldWMPPluginPath;
124 String newWMPPluginPath;
125
126 Vector<String>::const_iterator end = m_pluginDirectories.end();
127 for (Vector<String>::const_iterator it = m_pluginDirectories.begin(); it != end; ++it) {
128 String pattern = *it + "\\*";
129
130 hFind = FindFirstFileW(pattern.charactersWithNullTermination(), &findFileData);
131
132 if (hFind == INVALID_HANDLE_VALUE)
133 continue;
134
135 do {
136 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
137 continue;
138
139 String filename = String(findFileData.cFileName, wcslen(findFileData.cFileName));
140 if ((!filename.startsWith("np", false) || !filename.endsWith("dll", false)) &&
141 (!equalIgnoringCase(filename, "Plugin.dll") || !it->endsWith("Shockwave 10", false)))
142 continue;
143
144 String fullPath = *it + "\\" + filename;
145 if (!uniqueFilenames.add(fullPath).second)
146 continue;
147
148 paths.add(fullPath);
149
150 if (equalIgnoringCase(filename, "npdsplay.dll"))
151 oldWMPPluginPath = fullPath;
152 else if (equalIgnoringCase(filename, "np-mswmp.dll"))
153 newWMPPluginPath = fullPath;
154
155 } while (FindNextFileW(hFind, &findFileData) != 0);
156
157 FindClose(hFind);
158 }
159
160 addPluginPathsFromRegistry(HKEY_LOCAL_MACHINE, paths);
161 addPluginPathsFromRegistry(HKEY_CURRENT_USER, paths);
162
163 // If both the old and new WMP plugin are present in the plugins set,
164 // we remove the old one so we don't end up choosing the old one.
165 if (!oldWMPPluginPath.isEmpty() && !newWMPPluginPath.isEmpty())
166 paths.remove(oldWMPPluginPath);
167 }
168
parseVersionString(const String & versionString)169 static inline Vector<int> parseVersionString(const String& versionString)
170 {
171 Vector<int> version;
172
173 unsigned startPos = 0;
174 unsigned endPos;
175
176 while (startPos < versionString.length()) {
177 for (endPos = startPos; endPos < versionString.length(); ++endPos)
178 if (versionString[endPos] == '.' || versionString[endPos] == '_')
179 break;
180
181 int versionComponent = versionString.substring(startPos, endPos - startPos).toInt();
182 version.append(versionComponent);
183
184 startPos = endPos + 1;
185 }
186
187 return version;
188 }
189
190 // This returns whether versionA is higher than versionB
compareVersions(const Vector<int> & versionA,const Vector<int> & versionB)191 static inline bool compareVersions(const Vector<int>& versionA, const Vector<int>& versionB)
192 {
193 for (unsigned i = 0; i < versionA.size(); i++) {
194 if (i >= versionB.size())
195 return true;
196
197 if (versionA[i] > versionB[i])
198 return true;
199 else if (versionA[i] < versionB[i])
200 return false;
201 }
202
203 // If we come here, the versions are either the same or versionB has an extra component, just return false
204 return false;
205 }
206
addMozillaPluginDirectories(Vector<String> & directories)207 static inline void addMozillaPluginDirectories(Vector<String>& directories)
208 {
209 // Enumerate all Mozilla plugin directories in the registry
210 HKEY key;
211 LONG result;
212
213 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Mozilla"), 0, KEY_READ, &key);
214 if (result == ERROR_SUCCESS) {
215 WCHAR name[128];
216 FILETIME lastModified;
217
218 // Enumerate subkeys
219 for (int i = 0;; i++) {
220 DWORD nameLen = sizeof(name) / sizeof(WCHAR);
221 result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
222
223 if (result != ERROR_SUCCESS)
224 break;
225
226 String extensionsPath = String(name, nameLen) + "\\Extensions";
227 HKEY extensionsKey;
228
229 // Try opening the key
230 result = RegOpenKeyEx(key, extensionsPath.charactersWithNullTermination(), 0, KEY_READ, &extensionsKey);
231
232 if (result == ERROR_SUCCESS) {
233 // Now get the plugins directory
234 WCHAR pluginsDirectoryStr[_MAX_PATH];
235 DWORD pluginsDirectorySize = sizeof(pluginsDirectoryStr);
236 DWORD type;
237
238 result = RegQueryValueEx(extensionsKey, TEXT("Plugins"), 0, &type, (LPBYTE)&pluginsDirectoryStr, &pluginsDirectorySize);
239
240 if (result == ERROR_SUCCESS && type == REG_SZ)
241 directories.append(String(pluginsDirectoryStr, pluginsDirectorySize / sizeof(WCHAR) - 1));
242
243 RegCloseKey(extensionsKey);
244 }
245 }
246
247 RegCloseKey(key);
248 }
249 }
250
addWindowsMediaPlayerPluginDirectory(Vector<String> & directories)251 static inline void addWindowsMediaPlayerPluginDirectory(Vector<String>& directories)
252 {
253 #if !OS(WINCE)
254 // The new WMP Firefox plugin is installed in \PFiles\Plugins if it can't find any Firefox installs
255 WCHAR pluginDirectoryStr[_MAX_PATH + 1];
256 DWORD pluginDirectorySize = ::ExpandEnvironmentStringsW(TEXT("%SYSTEMDRIVE%\\PFiles\\Plugins"), pluginDirectoryStr, WTF_ARRAY_LENGTH(pluginDirectoryStr));
257
258 if (pluginDirectorySize > 0 && pluginDirectorySize <= WTF_ARRAY_LENGTH(pluginDirectoryStr))
259 directories.append(String(pluginDirectoryStr, pluginDirectorySize - 1));
260 #endif
261
262 DWORD type;
263 WCHAR installationDirectoryStr[_MAX_PATH];
264 DWORD installationDirectorySize = sizeof(installationDirectoryStr);
265
266 HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\MediaPlayer"), TEXT("Installation Directory"), &type, (LPBYTE)&installationDirectoryStr, &installationDirectorySize);
267
268 if (result == ERROR_SUCCESS && type == REG_SZ)
269 directories.append(String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1));
270 }
271
addQuickTimePluginDirectory(Vector<String> & directories)272 static inline void addQuickTimePluginDirectory(Vector<String>& directories)
273 {
274 DWORD type;
275 WCHAR installationDirectoryStr[_MAX_PATH];
276 DWORD installationDirectorySize = sizeof(installationDirectoryStr);
277
278 HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Apple Computer, Inc.\\QuickTime"), TEXT("InstallDir"), &type, (LPBYTE)&installationDirectoryStr, &installationDirectorySize);
279
280 if (result == ERROR_SUCCESS && type == REG_SZ) {
281 String pluginDir = String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1) + "\\plugins";
282 directories.append(pluginDir);
283 }
284 }
285
addAdobeAcrobatPluginDirectory(Vector<String> & directories)286 static inline void addAdobeAcrobatPluginDirectory(Vector<String>& directories)
287 {
288 HKEY key;
289 HRESULT result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Adobe\\Acrobat Reader"), 0, KEY_READ, &key);
290 if (result != ERROR_SUCCESS)
291 return;
292
293 WCHAR name[128];
294 FILETIME lastModified;
295
296 Vector<int> latestAcrobatVersion;
297 String latestAcrobatVersionString;
298
299 // Enumerate subkeys
300 for (int i = 0;; i++) {
301 DWORD nameLen = sizeof(name) / sizeof(WCHAR);
302 result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
303
304 if (result != ERROR_SUCCESS)
305 break;
306
307 Vector<int> acrobatVersion = parseVersionString(String(name, nameLen));
308 if (compareVersions(acrobatVersion, latestAcrobatVersion)) {
309 latestAcrobatVersion = acrobatVersion;
310 latestAcrobatVersionString = String(name, nameLen);
311 }
312 }
313
314 if (!latestAcrobatVersionString.isNull()) {
315 DWORD type;
316 WCHAR acrobatInstallPathStr[_MAX_PATH];
317 DWORD acrobatInstallPathSize = sizeof(acrobatInstallPathStr);
318
319 String acrobatPluginKeyPath = "Software\\Adobe\\Acrobat Reader\\" + latestAcrobatVersionString + "\\InstallPath";
320 result = SHGetValue(HKEY_LOCAL_MACHINE, acrobatPluginKeyPath.charactersWithNullTermination(), 0, &type, (LPBYTE)acrobatInstallPathStr, &acrobatInstallPathSize);
321
322 if (result == ERROR_SUCCESS) {
323 String acrobatPluginDirectory = String(acrobatInstallPathStr, acrobatInstallPathSize / sizeof(WCHAR) - 1) + "\\browser";
324 directories.append(acrobatPluginDirectory);
325 }
326 }
327
328 RegCloseKey(key);
329 }
330
addJavaPluginDirectory(Vector<String> & directories)331 static inline void addJavaPluginDirectory(Vector<String>& directories)
332 {
333 HKEY key;
334 HRESULT result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\JavaSoft\\Java Plug-in"), 0, KEY_READ, &key);
335 if (result != ERROR_SUCCESS)
336 return;
337
338 WCHAR name[128];
339 FILETIME lastModified;
340
341 Vector<int> latestJavaVersion;
342 String latestJavaVersionString;
343
344 // Enumerate subkeys
345 for (int i = 0;; i++) {
346 DWORD nameLen = sizeof(name) / sizeof(WCHAR);
347 result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
348
349 if (result != ERROR_SUCCESS)
350 break;
351
352 Vector<int> javaVersion = parseVersionString(String(name, nameLen));
353 if (compareVersions(javaVersion, latestJavaVersion)) {
354 latestJavaVersion = javaVersion;
355 latestJavaVersionString = String(name, nameLen);
356 }
357 }
358
359 if (!latestJavaVersionString.isEmpty()) {
360 DWORD type;
361 WCHAR javaInstallPathStr[_MAX_PATH];
362 DWORD javaInstallPathSize = sizeof(javaInstallPathStr);
363 DWORD useNewPluginValue;
364 DWORD useNewPluginSize;
365
366 String javaPluginKeyPath = "Software\\JavaSoft\\Java Plug-in\\" + latestJavaVersionString;
367 result = SHGetValue(HKEY_LOCAL_MACHINE, javaPluginKeyPath.charactersWithNullTermination(), TEXT("UseNewJavaPlugin"), &type, (LPVOID)&useNewPluginValue, &useNewPluginSize);
368
369 if (result == ERROR_SUCCESS && useNewPluginValue == 1) {
370 result = SHGetValue(HKEY_LOCAL_MACHINE, javaPluginKeyPath.charactersWithNullTermination(), TEXT("JavaHome"), &type, (LPBYTE)javaInstallPathStr, &javaInstallPathSize);
371 if (result == ERROR_SUCCESS) {
372 String javaPluginDirectory = String(javaInstallPathStr, javaInstallPathSize / sizeof(WCHAR) - 1) + "\\bin\\new_plugin";
373 directories.append(javaPluginDirectory);
374 }
375 }
376 }
377
378 RegCloseKey(key);
379 }
380
safariPluginsDirectory()381 static inline String safariPluginsDirectory()
382 {
383 WCHAR moduleFileNameStr[_MAX_PATH];
384 static String pluginsDirectory;
385 static bool cachedPluginDirectory = false;
386
387 if (!cachedPluginDirectory) {
388 cachedPluginDirectory = true;
389
390 int moduleFileNameLen = GetModuleFileName(0, moduleFileNameStr, _MAX_PATH);
391
392 if (!moduleFileNameLen || moduleFileNameLen == _MAX_PATH)
393 goto exit;
394
395 if (!PathRemoveFileSpec(moduleFileNameStr))
396 goto exit;
397
398 pluginsDirectory = String(moduleFileNameStr) + "\\Plugins";
399 }
400 exit:
401 return pluginsDirectory;
402 }
403
addMacromediaPluginDirectories(Vector<String> & directories)404 static inline void addMacromediaPluginDirectories(Vector<String>& directories)
405 {
406 #if !OS(WINCE)
407 WCHAR systemDirectoryStr[MAX_PATH];
408
409 if (!GetSystemDirectory(systemDirectoryStr, WTF_ARRAY_LENGTH(systemDirectoryStr)))
410 return;
411
412 WCHAR macromediaDirectoryStr[MAX_PATH];
413
414 PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Flash"));
415 directories.append(macromediaDirectoryStr);
416
417 PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Shockwave 10"));
418 directories.append(macromediaDirectoryStr);
419 #endif
420 }
421
defaultPluginDirectories()422 Vector<String> PluginDatabase::defaultPluginDirectories()
423 {
424 Vector<String> directories;
425 String ourDirectory = safariPluginsDirectory();
426
427 if (!ourDirectory.isNull())
428 directories.append(ourDirectory);
429 addQuickTimePluginDirectory(directories);
430 addAdobeAcrobatPluginDirectory(directories);
431 addMozillaPluginDirectories(directories);
432 addWindowsMediaPlayerPluginDirectory(directories);
433 addMacromediaPluginDirectories(directories);
434 #if PLATFORM(QT)
435 addJavaPluginDirectory(directories);
436 #endif
437
438 return directories;
439 }
440
isPreferredPluginDirectory(const String & directory)441 bool PluginDatabase::isPreferredPluginDirectory(const String& directory)
442 {
443 String ourDirectory = safariPluginsDirectory();
444
445 if (!ourDirectory.isNull() && !directory.isNull())
446 return ourDirectory == directory;
447
448 return false;
449 }
450
451 }
452