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 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 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 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 115 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 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 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 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 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 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 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 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 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 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 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 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