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