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 COMPILER(MINGW)
     38 #define _countof(x) (sizeof(x)/sizeof(x[0]))
     39 #endif
     40 
     41 #if OS(WINCE)
     42 // WINCE doesn't support Registry Key Access Rights. The parameter should always be 0
     43 #define KEY_ENUMERATE_SUB_KEYS 0
     44 
     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 
     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 
     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 
    117 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 
    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
    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 
    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 
    253 static inline void addWindowsMediaPlayerPluginDirectory(Vector<String>& directories)
    254 {
    255 #if !OS(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 
    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 
    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 
    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 
    356 static inline void addMacromediaPluginDirectories(Vector<String>& directories)
    357 {
    358 #if !OS(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 
    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 
    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