summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/Shared/Plugins/Netscape/mac/NetscapePluginModuleMac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/Shared/Plugins/Netscape/mac/NetscapePluginModuleMac.mm')
-rw-r--r--Source/WebKit2/Shared/Plugins/Netscape/mac/NetscapePluginModuleMac.mm338
1 files changed, 338 insertions, 0 deletions
diff --git a/Source/WebKit2/Shared/Plugins/Netscape/mac/NetscapePluginModuleMac.mm b/Source/WebKit2/Shared/Plugins/Netscape/mac/NetscapePluginModuleMac.mm
new file mode 100644
index 0000000..6ecacf0
--- /dev/null
+++ b/Source/WebKit2/Shared/Plugins/Netscape/mac/NetscapePluginModuleMac.mm
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 "NetscapePluginModule.h"
+
+#include <WebCore/WebCoreNSStringExtras.h>
+#include <wtf/HashSet.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+static bool getPluginArchitecture(CFBundleRef bundle, cpu_type_t& pluginArchitecture)
+{
+ RetainPtr<CFArrayRef> pluginArchitecturesArray(AdoptCF, CFBundleCopyExecutableArchitectures(bundle));
+ if (!pluginArchitecturesArray)
+ return false;
+
+ // Turn the array into a set.
+ HashSet<unsigned> architectures;
+ for (CFIndex i = 0, numPluginArchitectures = CFArrayGetCount(pluginArchitecturesArray.get()); i < numPluginArchitectures; ++i) {
+ CFNumberRef number = static_cast<CFNumberRef>(CFArrayGetValueAtIndex(pluginArchitecturesArray.get(), i));
+
+ SInt32 architecture;
+ if (!CFNumberGetValue(number, kCFNumberSInt32Type, &architecture))
+ continue;
+ architectures.add(architecture);
+ }
+
+#ifdef __x86_64__
+ // We only support 64-bit Intel plug-ins on 64-bit Intel.
+ if (architectures.contains(kCFBundleExecutableArchitectureX86_64)) {
+ pluginArchitecture = CPU_TYPE_X86_64;
+ return true;
+ }
+
+ // We also support 32-bit Intel plug-ins on 64-bit Intel.
+ if (architectures.contains(kCFBundleExecutableArchitectureI386)) {
+ pluginArchitecture = CPU_TYPE_X86;
+ return true;
+ }
+#elif defined(__i386__)
+ // We only support 32-bit Intel plug-ins on 32-bit Intel.
+ if (architectures.contains(kCFBundleExecutableArchitectureI386)) {
+ pluginArchitecture = CPU_TYPE_X86;
+ return true;
+ }
+#elif defined(__ppc64__)
+ // We only support 64-bit PPC plug-ins on 64-bit PPC.
+ if (architectures.contains(kCFBundleExecutableArchitecturePPC64)) {
+ pluginArchitecture = CPU_TYPE_POWERPC64;
+ return true;
+ }
+#elif defined(__ppc__)
+ // We only support 32-bit PPC plug-ins on 32-bit PPC.
+ if (architectures.contains(kCFBundleExecutableArchitecturePPC)) {
+ pluginArchitecture = CPU_TYPE_POWERPC;
+ return true;
+ }
+#else
+#error "Unhandled architecture"
+#endif
+
+ return false;
+}
+
+static bool getPluginInfoFromPropertyLists(CFBundleRef bundle, PluginInfo& pluginInfo)
+{
+ // FIXME: Handle WebPluginMIMETypesFilenameKey.
+
+ CFDictionaryRef mimeTypes = static_cast<CFDictionaryRef>(CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypes")));
+ if (!mimeTypes || CFGetTypeID(mimeTypes) != CFDictionaryGetTypeID())
+ return false;
+
+ // Get the plug-in name.
+ CFStringRef pluginName = static_cast<CFStringRef>(CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginName")));
+ if (pluginName && CFGetTypeID(pluginName) == CFStringGetTypeID())
+ pluginInfo.name = pluginName;
+
+ // Get the plug-in description.
+ CFStringRef pluginDescription = static_cast<CFStringRef>(CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginDescription")));
+ if (pluginDescription && CFGetTypeID(pluginDescription) == CFStringGetTypeID())
+ pluginInfo.desc = pluginDescription;
+
+ // Get the MIME type mapping dictionary.
+ CFIndex numMimeTypes = CFDictionaryGetCount(mimeTypes);
+ Vector<CFStringRef> mimeTypesVector(numMimeTypes);
+ Vector<CFDictionaryRef> mimeTypeInfoVector(numMimeTypes);
+ CFDictionaryGetKeysAndValues(mimeTypes, reinterpret_cast<const void**>(mimeTypesVector.data()), reinterpret_cast<const void**>(mimeTypeInfoVector.data()));
+
+ for (CFIndex i = 0; i < numMimeTypes; ++i) {
+ MimeClassInfo mimeClassInfo;
+
+ // If this MIME type is invalid, ignore it.
+ CFStringRef mimeType = mimeTypesVector[i];
+ if (!mimeType || CFGetTypeID(mimeType) != CFStringGetTypeID() || CFStringGetLength(mimeType) == 0)
+ continue;
+
+ // If this MIME type doesn't have a valid info dictionary, ignore it.
+ CFDictionaryRef mimeTypeInfo = mimeTypeInfoVector[i];
+ if (!mimeTypeInfo || CFGetTypeID(mimeTypeInfo) != CFDictionaryGetTypeID())
+ continue;
+
+ // Get the MIME type description.
+ CFStringRef mimeTypeDescription = static_cast<CFStringRef>(CFDictionaryGetValue(mimeTypeInfo, CFSTR("WebPluginTypeDescription")));
+ if (mimeTypeDescription && CFGetTypeID(mimeTypeDescription) != CFStringGetTypeID())
+ mimeTypeDescription = 0;
+
+ mimeClassInfo.type = String(mimeType).lower();
+ mimeClassInfo.desc = mimeTypeDescription;
+
+ // Now get the extensions for this MIME type.
+ CFIndex numExtensions = 0;
+ CFArrayRef extensionsArray = static_cast<CFArrayRef>(CFDictionaryGetValue(mimeTypeInfo, CFSTR("WebPluginExtensions")));
+ if (extensionsArray && CFGetTypeID(extensionsArray) == CFArrayGetTypeID())
+ numExtensions = CFArrayGetCount(extensionsArray);
+
+ for (CFIndex i = 0; i < numExtensions; ++i) {
+ CFStringRef extension = static_cast<CFStringRef>(CFArrayGetValueAtIndex(extensionsArray, i));
+ if (!extension || CFGetTypeID(extension) != CFStringGetTypeID())
+ continue;
+
+ mimeClassInfo.extensions.append(String(extension).lower());
+ }
+
+ // Add this MIME type.
+ pluginInfo.mimes.append(mimeClassInfo);
+ }
+
+ return true;
+}
+
+class ResourceMap {
+public:
+ explicit ResourceMap(CFBundleRef bundle)
+ : m_bundle(bundle)
+ , m_currentResourceFile(CurResFile())
+ , m_bundleResourceMap(CFBundleOpenBundleResourceMap(m_bundle))
+ {
+ UseResFile(m_bundleResourceMap);
+ }
+
+ ~ResourceMap()
+ {
+ // Close the resource map.
+ CFBundleCloseBundleResourceMap(m_bundle, m_bundleResourceMap);
+
+ // And restore the old resource.
+ UseResFile(m_currentResourceFile);
+ }
+
+ bool isValid() const { return m_bundleResourceMap != -1; }
+
+private:
+ CFBundleRef m_bundle;
+ ResFileRefNum m_currentResourceFile;
+ ResFileRefNum m_bundleResourceMap;
+};
+
+static bool getStringListResource(ResID resourceID, Vector<String>& stringList) {
+ Handle stringListHandle = Get1Resource('STR#', resourceID);
+ if (!stringListHandle || !*stringListHandle)
+ return false;
+
+ // Get the string list size.
+ Size stringListSize = GetHandleSize(stringListHandle);
+ if (stringListSize < static_cast<Size>(sizeof(UInt16)))
+ return false;
+
+ CFStringEncoding stringEncoding = stringEncodingForResource(stringListHandle);
+
+ unsigned char* ptr = reinterpret_cast<unsigned char*>(*stringListHandle);
+ unsigned char* end = ptr + stringListSize;
+
+ // Get the number of strings in the string list.
+ UInt16 numStrings = *reinterpret_cast<UInt16*>(ptr);
+ ptr += sizeof(UInt16);
+
+ for (UInt16 i = 0; i < numStrings; ++i) {
+ // We're past the end of the string, bail.
+ if (ptr >= end)
+ return false;
+
+ // Get the string length.
+ unsigned char stringLength = *ptr++;
+
+ RetainPtr<CFStringRef> cfString(AdoptCF, CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, ptr, stringLength, stringEncoding, false, kCFAllocatorNull));
+ if (!cfString.get())
+ return false;
+
+ stringList.append(cfString.get());
+ ptr += stringLength;
+ }
+
+ if (ptr != end)
+ return false;
+
+ return true;
+}
+
+static const ResID PluginNameOrDescriptionStringNumber = 126;
+static const ResID MIMEDescriptionStringNumber = 127;
+static const ResID MIMEListStringStringNumber = 128;
+
+static bool getPluginInfoFromCarbonResources(CFBundleRef bundle, PluginInfo& pluginInfo)
+{
+ ResourceMap resourceMap(bundle);
+ if (!resourceMap.isValid())
+ return false;
+
+ // Get the description and name string list.
+ Vector<String> descriptionAndName;
+ if (!getStringListResource(PluginNameOrDescriptionStringNumber, descriptionAndName))
+ return false;
+
+ // Get the MIME types and extensions string list. This list needs to be a multiple of two.
+ Vector<String> mimeTypesAndExtensions;
+ if (!getStringListResource(MIMEListStringStringNumber, mimeTypesAndExtensions))
+ return false;
+
+ if (mimeTypesAndExtensions.size() % 2)
+ return false;
+
+ size_t numMimeTypes = mimeTypesAndExtensions.size() / 2;
+
+ // Now get the MIME type descriptions string list. This string list needs to be the same length as the number of MIME types.
+ Vector<String> mimeTypeDescriptions;
+ if (!getStringListResource(MIMEDescriptionStringNumber, mimeTypeDescriptions))
+ return false;
+
+ if (mimeTypeDescriptions.size() != numMimeTypes)
+ return false;
+
+ // Add all MIME types.
+ for (size_t i = 0; i < mimeTypesAndExtensions.size() / 2; ++i) {
+ MimeClassInfo mimeClassInfo;
+
+ const String& mimeType = mimeTypesAndExtensions[i * 2];
+ const String& description = mimeTypeDescriptions[i];
+
+ mimeClassInfo.type = mimeType.lower();
+ mimeClassInfo.desc = description;
+
+ Vector<String> extensions;
+ mimeTypesAndExtensions[i * 2 + 1].split(',', extensions);
+
+ for (size_t i = 0; i < extensions.size(); ++i)
+ mimeClassInfo.extensions.append(extensions[i].lower());
+
+ pluginInfo.mimes.append(mimeClassInfo);
+ }
+
+ // Set the description and name if they exist.
+ if (descriptionAndName.size() > 0)
+ pluginInfo.desc = descriptionAndName[0];
+ if (descriptionAndName.size() > 1)
+ pluginInfo.name = descriptionAndName[1];
+
+ return true;
+}
+
+bool NetscapePluginModule::getPluginInfo(const String& pluginPath, PluginInfoStore::Plugin& plugin)
+{
+ RetainPtr<CFStringRef> bundlePath(AdoptCF, pluginPath.createCFString());
+ RetainPtr<CFURLRef> bundleURL(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundlePath.get(), kCFURLPOSIXPathStyle, false));
+
+ // Try to initialize the bundle.
+ RetainPtr<CFBundleRef> bundle(AdoptCF, CFBundleCreate(kCFAllocatorDefault, bundleURL.get()));
+ if (!bundle)
+ return false;
+
+ // Check if this bundle is an NPAPI plug-in.
+ UInt32 packageType = 0;
+ CFBundleGetPackageInfo(bundle.get(), &packageType, 0);
+ if (packageType != FOUR_CHAR_CODE('BRPL'))
+ return false;
+
+ // Check that the architecture is valid.
+ cpu_type_t pluginArchitecture = 0;
+ if (!getPluginArchitecture(bundle.get(), pluginArchitecture))
+ return false;
+
+ // Check that there's valid info for this plug-in.
+ if (!getPluginInfoFromPropertyLists(bundle.get(), plugin.info) &&
+ !getPluginInfoFromCarbonResources(bundle.get(), plugin.info))
+ return false;
+
+ plugin.path = pluginPath;
+ plugin.pluginArchitecture = pluginArchitecture;
+ plugin.bundleIdentifier = CFBundleGetIdentifier(bundle.get());
+ plugin.versionNumber = CFBundleGetVersionNumber(bundle.get());
+
+ RetainPtr<CFStringRef> filename(AdoptCF, CFURLCopyLastPathComponent(bundleURL.get()));
+ plugin.info.file = filename.get();
+
+ if (plugin.info.name.isNull())
+ plugin.info.name = plugin.info.file;
+ if (plugin.info.desc.isNull())
+ plugin.info.desc = plugin.info.file;
+
+ return true;
+}
+
+void NetscapePluginModule::determineQuirks()
+{
+ PluginInfoStore::Plugin plugin;
+ if (!getPluginInfo(m_pluginPath, plugin))
+ return;
+
+ if (plugin.bundleIdentifier == "com.macromedia.Flash Player.plugin") {
+ // Flash requires that the return value of getprogname() be "WebKitPluginHost".
+ m_pluginQuirks.add(PluginQuirks::PrognameShouldBeWebKitPluginHost);
+ }
+}
+
+} // namespace WebKit