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