/* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2008 Collabora Ltd. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "PluginPackage.h" #include <wtf/RetainPtr.h> #include "MIMETypeRegistry.h" #include "npruntime_impl.h" #include "PluginDatabase.h" #include "PluginDebug.h" #include "WebCoreNSStringExtras.h" #include <wtf/text/CString.h> #include <CoreFoundation/CoreFoundation.h> #define PluginNameOrDescriptionStringNumber 126 #define MIMEDescriptionStringNumber 127 #define MIMEListStringStringNumber 128 namespace WebCore { void PluginPackage::determineQuirks(const String& mimeType) { if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) { // Because a single process cannot create multiple VMs, and we cannot reliably unload a // Java VM, we cannot unload the Java Plugin, or we'll lose reference to our only VM m_quirks.add(PluginQuirkDontUnloadPlugin); // Setting the window region to an empty region causes bad scrolling repaint problems // with the Java plug-in. m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling); } if (mimeType == "application/x-shockwave-flash") { // The flash plugin only requests windowless plugins if we return a mozilla user agent m_quirks.add(PluginQuirkWantsMozillaUserAgent); m_quirks.add(PluginQuirkThrottleInvalidate); m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages); m_quirks.add(PluginQuirkFlashURLNotifyBug); } } typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void); static WTF::RetainPtr<CFDictionaryRef> readPListFile(CFStringRef fileName, bool createFile, CFBundleRef bundle) { if (createFile) { BP_CreatePluginMIMETypesPreferencesFuncPtr funcPtr = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("BP_CreatePluginMIMETypesPreferences")); if (funcPtr) funcPtr(); } WTF::RetainPtr<CFDictionaryRef> map; WTF::RetainPtr<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, fileName, kCFURLPOSIXPathStyle, false); CFDataRef resource = 0; SInt32 code; if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url.get(), &resource, 0, 0, &code)) return map; WTF::RetainPtr<CFPropertyListRef> propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource, kCFPropertyListImmutable, 0); CFRelease(resource); if (!propertyList) return map; if (CFGetTypeID(propertyList.get()) != CFDictionaryGetTypeID()) return map; map = static_cast<CFDictionaryRef>(static_cast<CFPropertyListRef>(propertyList.get())); return map; } static Vector<String> stringListFromResourceId(SInt16 id) { Vector<String> list; Handle handle = Get1Resource('STR#', id); if (!handle) return list; CFStringEncoding encoding = stringEncodingForResource(handle); unsigned char* p = (unsigned char*)*handle; if (!p) return list; SInt16 count = *(SInt16*)p; p += sizeof(SInt16); for (SInt16 i = 0; i < count; ++i) { unsigned char length = *p; WTF::RetainPtr<CFStringRef> str = CFStringCreateWithPascalString(0, p, encoding); list.append(str.get()); p += 1 + length; } return list; } bool PluginPackage::fetchInfo() { if (!load()) return false; WTF::RetainPtr<CFDictionaryRef> mimeDict; WTF::RetainPtr<CFTypeRef> mimeTypesFileName = CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypesFilename")); if (mimeTypesFileName && CFGetTypeID(mimeTypesFileName.get()) == CFStringGetTypeID()) { WTF::RetainPtr<CFStringRef> fileName = (CFStringRef)mimeTypesFileName.get(); WTF::RetainPtr<CFStringRef> homeDir = homeDirectoryPath().createCFString(); WTF::RetainPtr<CFStringRef> path = CFStringCreateWithFormat(0, 0, CFSTR("%@/Library/Preferences/%@"), homeDir.get(), fileName.get()); WTF::RetainPtr<CFDictionaryRef> plist = readPListFile(path.get(), /*createFile*/ false, m_module); if (plist) { // If the plist isn't localized, have the plug-in recreate it in the preferred language. WTF::RetainPtr<CFStringRef> localizationName = (CFStringRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginLocalizationName")); CFLocaleRef locale = CFLocaleCopyCurrent(); if (localizationName != CFLocaleGetIdentifier(locale)) plist = readPListFile(path.get(), /*createFile*/ true, m_module); CFRelease(locale); } else { // Plist doesn't exist, ask the plug-in to create it. plist = readPListFile(path.get(), /*createFile*/ true, m_module); } if (plist) mimeDict = (CFDictionaryRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginMIMETypes")); } if (!mimeDict) mimeDict = (CFDictionaryRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypes")); if (mimeDict) { CFIndex propCount = CFDictionaryGetCount(mimeDict.get()); Vector<const void*, 128> keys(propCount); Vector<const void*, 128> values(propCount); CFDictionaryGetKeysAndValues(mimeDict.get(), keys.data(), values.data()); for (int i = 0; i < propCount; ++i) { String mimeType = (CFStringRef)keys[i]; mimeType = mimeType.lower(); WTF::RetainPtr<CFDictionaryRef> extensionsDict = (CFDictionaryRef)values[i]; WTF::RetainPtr<CFNumberRef> enabled = (CFNumberRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeEnabled")); if (enabled) { int enabledValue = 0; if (CFNumberGetValue(enabled.get(), kCFNumberIntType, &enabledValue) && enabledValue == 0) continue; } Vector<String> mimeExtensions; WTF::RetainPtr<CFArrayRef> extensions = (CFArrayRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginExtensions")); if (extensions) { CFIndex extensionCount = CFArrayGetCount(extensions.get()); for (CFIndex i = 0; i < extensionCount; ++i) { String extension =(CFStringRef)CFArrayGetValueAtIndex(extensions.get(), i); extension = extension.lower(); mimeExtensions.append(extension); } } m_mimeToExtensions.set(mimeType, mimeExtensions); String description = (CFStringRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeDescription")); m_mimeToDescriptions.set(mimeType, description); } m_name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginName")); m_description = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginDescription")); } else { int resFile = CFBundleOpenBundleResourceMap(m_module); UseResFile(resFile); Vector<String> mimes = stringListFromResourceId(MIMEListStringStringNumber); if (mimes.size() % 2 != 0) return false; Vector<String> descriptions = stringListFromResourceId(MIMEDescriptionStringNumber); if (descriptions.size() != mimes.size() / 2) return false; for (size_t i = 0; i < mimes.size(); i += 2) { String mime = mimes[i].lower(); Vector<String> extensions; mimes[i + 1].lower().split(UChar(','), extensions); m_mimeToExtensions.set(mime, extensions); m_mimeToDescriptions.set(mime, descriptions[i / 2]); } Vector<String> names = stringListFromResourceId(PluginNameOrDescriptionStringNumber); if (names.size() == 2) { m_description = names[0]; m_name = names[1]; } CFBundleCloseBundleResourceMap(m_module, resFile); } LOG(Plugins, "PluginPackage::fetchInfo(): Found plug-in '%s'", m_name.utf8().data()); if (isPluginBlacklisted()) { LOG(Plugins, "\tPlug-in is blacklisted!"); return false; } return true; } bool PluginPackage::isPluginBlacklisted() { return false; } bool PluginPackage::load() { if (m_isLoaded) { m_loadCount++; return true; } WTF::RetainPtr<CFStringRef> path(AdoptCF, m_path.createCFString()); WTF::RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false)); m_module = CFBundleCreate(NULL, url.get()); if (!m_module || !CFBundleLoadExecutable(m_module)) { LOG(Plugins, "%s not loaded", m_path.utf8().data()); return false; } m_isLoaded = true; NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0; NP_InitializeFuncPtr NP_Initialize; NPError npErr; NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Initialize")); NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_GetEntryPoints")); m_NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Shutdown")); if (!NP_Initialize || !NP_GetEntryPoints || !m_NPP_Shutdown) goto abort; memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); m_pluginFuncs.size = sizeof(m_pluginFuncs); initializeBrowserFuncs(); npErr = NP_Initialize(&m_browserFuncs); LOG_NPERROR(npErr); if (npErr != NPERR_NO_ERROR) goto abort; npErr = NP_GetEntryPoints(&m_pluginFuncs); LOG_NPERROR(npErr); if (npErr != NPERR_NO_ERROR) goto abort; m_loadCount++; return true; abort: unloadWithoutShutdown(); return false; } uint16_t PluginPackage::NPVersion() const { return NP_VERSION_MINOR; } } // namespace WebCore