Home | History | Annotate | Download | only in win
      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