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