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