WebCore/plugins/mac/PluginPackageMac.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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