Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2008 Collabora Ltd. All rights reserved.
      4  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
      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 "PluginPackage.h"
     30 
     31 #include <wtf/RetainPtr.h>
     32 #include "MIMETypeRegistry.h"
     33 #include "npruntime_impl.h"
     34 #include "PluginDatabase.h"
     35 #include "PluginDebug.h"
     36 #include "WebCoreNSStringExtras.h"
     37 #include <wtf/text/CString.h>
     38 
     39 #include <CoreFoundation/CoreFoundation.h>
     40 
     41 #define PluginNameOrDescriptionStringNumber     126
     42 #define MIMEDescriptionStringNumber             127
     43 #define MIMEListStringStringNumber              128
     44 
     45 namespace WebCore {
     46 
     47 void PluginPackage::determineQuirks(const String& mimeType)
     48 {
     49     if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) {
     50         // Because a single process cannot create multiple VMs, and we cannot reliably unload a
     51         // Java VM, we cannot unload the Java Plugin, or we'll lose reference to our only VM
     52         m_quirks.add(PluginQuirkDontUnloadPlugin);
     53 
     54         // Setting the window region to an empty region causes bad scrolling repaint problems
     55         // with the Java plug-in.
     56         m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling);
     57     }
     58 
     59     if (mimeType == "application/x-shockwave-flash") {
     60         // The flash plugin only requests windowless plugins if we return a mozilla user agent
     61         m_quirks.add(PluginQuirkWantsMozillaUserAgent);
     62         m_quirks.add(PluginQuirkThrottleInvalidate);
     63         m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages);
     64         m_quirks.add(PluginQuirkFlashURLNotifyBug);
     65     }
     66 
     67 }
     68 
     69 typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void);
     70 
     71 static WTF::RetainPtr<CFDictionaryRef> readPListFile(CFStringRef fileName, bool createFile, CFBundleRef bundle)
     72 {
     73     if (createFile) {
     74         BP_CreatePluginMIMETypesPreferencesFuncPtr funcPtr =
     75             (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("BP_CreatePluginMIMETypesPreferences"));
     76         if (funcPtr)
     77             funcPtr();
     78     }
     79 
     80     WTF::RetainPtr<CFDictionaryRef> map;
     81     WTF::RetainPtr<CFURLRef> url =
     82         CFURLCreateWithFileSystemPath(kCFAllocatorDefault, fileName, kCFURLPOSIXPathStyle, false);
     83 
     84     CFDataRef resource = 0;
     85     SInt32 code;
     86     if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url.get(), &resource, 0, 0, &code))
     87         return map;
     88 
     89     WTF::RetainPtr<CFPropertyListRef> propertyList =
     90             CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource, kCFPropertyListImmutable, 0);
     91 
     92     CFRelease(resource);
     93 
     94     if (!propertyList)
     95         return map;
     96 
     97     if (CFGetTypeID(propertyList.get()) != CFDictionaryGetTypeID())
     98         return map;
     99 
    100     map = static_cast<CFDictionaryRef>(static_cast<CFPropertyListRef>(propertyList.get()));
    101     return map;
    102 }
    103 
    104 static Vector<String> stringListFromResourceId(SInt16 id)
    105 {
    106     Vector<String> list;
    107 
    108     Handle handle = Get1Resource('STR#', id);
    109     if (!handle)
    110         return list;
    111 
    112     CFStringEncoding encoding = stringEncodingForResource(handle);
    113 
    114     unsigned char* p = (unsigned char*)*handle;
    115     if (!p)
    116         return list;
    117 
    118     SInt16 count = *(SInt16*)p;
    119     p += sizeof(SInt16);
    120 
    121     for (SInt16 i = 0; i < count; ++i) {
    122         unsigned char length = *p;
    123         WTF::RetainPtr<CFStringRef> str = CFStringCreateWithPascalString(0, p, encoding);
    124         list.append(str.get());
    125         p += 1 + length;
    126     }
    127 
    128     return list;
    129 }
    130 
    131 bool PluginPackage::fetchInfo()
    132 {
    133     if (!load())
    134         return false;
    135 
    136     WTF::RetainPtr<CFDictionaryRef> mimeDict;
    137 
    138     WTF::RetainPtr<CFTypeRef> mimeTypesFileName = CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypesFilename"));
    139     if (mimeTypesFileName && CFGetTypeID(mimeTypesFileName.get()) == CFStringGetTypeID()) {
    140 
    141         WTF::RetainPtr<CFStringRef> fileName = (CFStringRef)mimeTypesFileName.get();
    142         WTF::RetainPtr<CFStringRef> homeDir = homeDirectoryPath().createCFString();
    143         WTF::RetainPtr<CFStringRef> path = CFStringCreateWithFormat(0, 0, CFSTR("%@/Library/Preferences/%@"), homeDir.get(), fileName.get());
    144 
    145         WTF::RetainPtr<CFDictionaryRef> plist = readPListFile(path.get(), /*createFile*/ false, m_module);
    146         if (plist) {
    147             // If the plist isn't localized, have the plug-in recreate it in the preferred language.
    148             WTF::RetainPtr<CFStringRef> localizationName =
    149                 (CFStringRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginLocalizationName"));
    150             CFLocaleRef locale = CFLocaleCopyCurrent();
    151             if (localizationName != CFLocaleGetIdentifier(locale))
    152                 plist = readPListFile(path.get(), /*createFile*/ true, m_module);
    153 
    154             CFRelease(locale);
    155         } else {
    156             // Plist doesn't exist, ask the plug-in to create it.
    157             plist = readPListFile(path.get(), /*createFile*/ true, m_module);
    158         }
    159 
    160         if (plist)
    161             mimeDict = (CFDictionaryRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginMIMETypes"));
    162     }
    163 
    164     if (!mimeDict)
    165         mimeDict = (CFDictionaryRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypes"));
    166 
    167     if (mimeDict) {
    168         CFIndex propCount = CFDictionaryGetCount(mimeDict.get());
    169         Vector<const void*, 128> keys(propCount);
    170         Vector<const void*, 128> values(propCount);
    171         CFDictionaryGetKeysAndValues(mimeDict.get(), keys.data(), values.data());
    172         for (int i = 0; i < propCount; ++i) {
    173             String mimeType = (CFStringRef)keys[i];
    174             mimeType = mimeType.lower();
    175 
    176             WTF::RetainPtr<CFDictionaryRef> extensionsDict = (CFDictionaryRef)values[i];
    177 
    178             WTF::RetainPtr<CFNumberRef> enabled = (CFNumberRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeEnabled"));
    179             if (enabled) {
    180                 int enabledValue = 0;
    181                 if (CFNumberGetValue(enabled.get(), kCFNumberIntType, &enabledValue) && enabledValue == 0)
    182                     continue;
    183             }
    184 
    185             Vector<String> mimeExtensions;
    186             WTF::RetainPtr<CFArrayRef> extensions = (CFArrayRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginExtensions"));
    187             if (extensions) {
    188                 CFIndex extensionCount = CFArrayGetCount(extensions.get());
    189                 for (CFIndex i = 0; i < extensionCount; ++i) {
    190                     String extension =(CFStringRef)CFArrayGetValueAtIndex(extensions.get(), i);
    191                     extension = extension.lower();
    192                     mimeExtensions.append(extension);
    193                 }
    194             }
    195             m_mimeToExtensions.set(mimeType, mimeExtensions);
    196 
    197             String description = (CFStringRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeDescription"));
    198             m_mimeToDescriptions.set(mimeType, description);
    199         }
    200 
    201         m_name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginName"));
    202         m_description = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginDescription"));
    203 
    204     } else {
    205         int resFile = CFBundleOpenBundleResourceMap(m_module);
    206 
    207         UseResFile(resFile);
    208 
    209         Vector<String> mimes = stringListFromResourceId(MIMEListStringStringNumber);
    210 
    211         if (mimes.size() % 2 != 0)
    212             return false;
    213 
    214         Vector<String> descriptions = stringListFromResourceId(MIMEDescriptionStringNumber);
    215         if (descriptions.size() != mimes.size() / 2)
    216             return false;
    217 
    218         for (size_t i = 0;  i < mimes.size(); i += 2) {
    219             String mime = mimes[i].lower();
    220             Vector<String> extensions;
    221             mimes[i + 1].lower().split(UChar(','), extensions);
    222 
    223             m_mimeToExtensions.set(mime, extensions);
    224 
    225             m_mimeToDescriptions.set(mime, descriptions[i / 2]);
    226         }
    227 
    228         Vector<String> names = stringListFromResourceId(PluginNameOrDescriptionStringNumber);
    229         if (names.size() == 2) {
    230             m_description = names[0];
    231             m_name = names[1];
    232         }
    233 
    234         CFBundleCloseBundleResourceMap(m_module, resFile);
    235     }
    236 
    237     LOG(Plugins, "PluginPackage::fetchInfo(): Found plug-in '%s'", m_name.utf8().data());
    238     if (isPluginBlacklisted()) {
    239         LOG(Plugins, "\tPlug-in is blacklisted!");
    240         return false;
    241     }
    242 
    243     return true;
    244 }
    245 
    246 bool PluginPackage::isPluginBlacklisted()
    247 {
    248     return false;
    249 }
    250 
    251 bool PluginPackage::load()
    252 {
    253     if (m_isLoaded) {
    254         m_loadCount++;
    255         return true;
    256     }
    257 
    258     WTF::RetainPtr<CFStringRef> path(AdoptCF, m_path.createCFString());
    259     WTF::RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(),
    260                                                                         kCFURLPOSIXPathStyle, false));
    261     m_module = CFBundleCreate(NULL, url.get());
    262     if (!m_module || !CFBundleLoadExecutable(m_module)) {
    263         LOG(Plugins, "%s not loaded", m_path.utf8().data());
    264         return false;
    265     }
    266 
    267     m_isLoaded = true;
    268 
    269     NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0;
    270     NP_InitializeFuncPtr NP_Initialize;
    271     NPError npErr;
    272 
    273     NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Initialize"));
    274     NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_GetEntryPoints"));
    275     m_NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Shutdown"));
    276 
    277     if (!NP_Initialize || !NP_GetEntryPoints || !m_NPP_Shutdown)
    278         goto abort;
    279 
    280     memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
    281     m_pluginFuncs.size = sizeof(m_pluginFuncs);
    282 
    283     initializeBrowserFuncs();
    284 
    285     npErr = NP_Initialize(&m_browserFuncs);
    286     LOG_NPERROR(npErr);
    287     if (npErr != NPERR_NO_ERROR)
    288         goto abort;
    289 
    290     npErr = NP_GetEntryPoints(&m_pluginFuncs);
    291     LOG_NPERROR(npErr);
    292     if (npErr != NPERR_NO_ERROR)
    293         goto abort;
    294 
    295     m_loadCount++;
    296     return true;
    297 
    298 abort:
    299     unloadWithoutShutdown();
    300     return false;
    301 }
    302 
    303 uint16_t PluginPackage::NPVersion() const
    304 {
    305     return NP_VERSION_MINOR;
    306 }
    307 } // namespace WebCore
    308