summaryrefslogtreecommitdiff
path: root/dom/plugins/base/nsPluginsDirDarwin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/plugins/base/nsPluginsDirDarwin.cpp')
-rw-r--r--dom/plugins/base/nsPluginsDirDarwin.cpp572
1 files changed, 572 insertions, 0 deletions
diff --git a/dom/plugins/base/nsPluginsDirDarwin.cpp b/dom/plugins/base/nsPluginsDirDarwin.cpp
new file mode 100644
index 0000000000..0085eec0d6
--- /dev/null
+++ b/dom/plugins/base/nsPluginsDirDarwin.cpp
@@ -0,0 +1,572 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ nsPluginsDirDarwin.cpp
+
+ Mac OS X implementation of the nsPluginsDir/nsPluginsFile classes.
+
+ by Patrick C. Beard.
+ */
+
+#include "GeckoChildProcessHost.h"
+#include "base/process_util.h"
+
+#include "prlink.h"
+#include "prnetdb.h"
+#include "nsXPCOM.h"
+
+#include "nsPluginsDir.h"
+#include "nsNPAPIPlugin.h"
+#include "nsPluginsDirUtils.h"
+
+#include "nsILocalFileMac.h"
+#include "mozilla/UniquePtr.h"
+
+#include "nsCocoaFeatures.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+
+typedef NS_NPAPIPLUGIN_CALLBACK(const char *, NP_GETMIMEDESCRIPTION) ();
+typedef NS_NPAPIPLUGIN_CALLBACK(OSErr, BP_GETSUPPORTEDMIMETYPES) (BPSupportedMIMETypes *mimeInfo, UInt32 flags);
+
+/*
+** Returns a CFBundleRef if the path refers to a Mac OS X bundle directory.
+** The caller is responsible for calling CFRelease() to deallocate.
+*/
+static CFBundleRef getPluginBundle(const char* path)
+{
+ CFBundleRef bundle = nullptr;
+ CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, path,
+ kCFStringEncodingUTF8);
+ if (pathRef) {
+ CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef,
+ kCFURLPOSIXPathStyle,
+ true);
+ if (bundleURL) {
+ bundle = ::CFBundleCreate(nullptr, bundleURL);
+ ::CFRelease(bundleURL);
+ }
+ ::CFRelease(pathRef);
+ }
+ return bundle;
+}
+
+static nsresult toCFURLRef(nsIFile* file, CFURLRef& outURL)
+{
+ nsCOMPtr<nsILocalFileMac> lfm = do_QueryInterface(file);
+ if (!lfm)
+ return NS_ERROR_FAILURE;
+ CFURLRef url;
+ nsresult rv = lfm->GetCFURL(&url);
+ if (NS_SUCCEEDED(rv))
+ outURL = url;
+
+ return rv;
+}
+
+bool nsPluginsDir::IsPluginFile(nsIFile* file)
+{
+ nsCString fileName;
+ file->GetNativeLeafName(fileName);
+ /*
+ * Don't load the VDP fake plugin, to avoid tripping a bad bug in OS X
+ * 10.5.3 (see bug 436575).
+ */
+ if (!strcmp(fileName.get(), "VerifiedDownloadPlugin.plugin")) {
+ NS_WARNING("Preventing load of VerifiedDownloadPlugin.plugin (see bug 436575)");
+ return false;
+ }
+ return true;
+}
+
+// Caller is responsible for freeing returned buffer.
+static char* CFStringRefToUTF8Buffer(CFStringRef cfString)
+{
+ const char* buffer = ::CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8);
+ if (buffer) {
+ return PL_strdup(buffer);
+ }
+
+ int bufferLength =
+ ::CFStringGetMaximumSizeForEncoding(::CFStringGetLength(cfString),
+ kCFStringEncodingUTF8) + 1;
+ char* newBuffer = static_cast<char*>(moz_xmalloc(bufferLength));
+ if (!newBuffer) {
+ return nullptr;
+ }
+
+ if (!::CFStringGetCString(cfString, newBuffer, bufferLength,
+ kCFStringEncodingUTF8)) {
+ free(newBuffer);
+ return nullptr;
+ }
+
+ newBuffer = static_cast<char*>(moz_xrealloc(newBuffer,
+ strlen(newBuffer) + 1));
+ return newBuffer;
+}
+
+class AutoCFTypeObject {
+public:
+ explicit AutoCFTypeObject(CFTypeRef aObject)
+ {
+ mObject = aObject;
+ }
+ ~AutoCFTypeObject()
+ {
+ ::CFRelease(mObject);
+ }
+private:
+ CFTypeRef mObject;
+};
+
+static Boolean MimeTypeEnabled(CFDictionaryRef mimeDict) {
+ if (!mimeDict) {
+ return true;
+ }
+
+ CFTypeRef value;
+ if (::CFDictionaryGetValueIfPresent(mimeDict, CFSTR("WebPluginTypeEnabled"), &value)) {
+ if (value && ::CFGetTypeID(value) == ::CFBooleanGetTypeID()) {
+ return ::CFBooleanGetValue(static_cast<CFBooleanRef>(value));
+ }
+ }
+ return true;
+}
+
+static CFDictionaryRef ParsePlistForMIMETypesFilename(CFBundleRef bundle)
+{
+ CFTypeRef mimeFileName = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypesFilename"));
+ if (!mimeFileName || ::CFGetTypeID(mimeFileName) != ::CFStringGetTypeID()) {
+ return nullptr;
+ }
+
+ FSRef homeDir;
+ if (::FSFindFolder(kUserDomain, kCurrentUserFolderType, kDontCreateFolder, &homeDir) != noErr) {
+ return nullptr;
+ }
+
+ CFURLRef userDirURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, &homeDir);
+ if (!userDirURL) {
+ return nullptr;
+ }
+
+ AutoCFTypeObject userDirURLAutorelease(userDirURL);
+ CFStringRef mimeFilePath = ::CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("Library/Preferences/%@"), static_cast<CFStringRef>(mimeFileName));
+ if (!mimeFilePath) {
+ return nullptr;
+ }
+
+ AutoCFTypeObject mimeFilePathAutorelease(mimeFilePath);
+ CFURLRef mimeFileURL = ::CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, mimeFilePath, kCFURLPOSIXPathStyle, false, userDirURL);
+ if (!mimeFileURL) {
+ return nullptr;
+ }
+
+ AutoCFTypeObject mimeFileURLAutorelease(mimeFileURL);
+ SInt32 errorCode = 0;
+ CFDataRef mimeFileData = nullptr;
+ Boolean result = ::CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, mimeFileURL, &mimeFileData, nullptr, nullptr, &errorCode);
+ if (!result) {
+ return nullptr;
+ }
+
+ AutoCFTypeObject mimeFileDataAutorelease(mimeFileData);
+ if (errorCode != 0) {
+ return nullptr;
+ }
+
+ CFPropertyListRef propertyList = ::CFPropertyListCreateFromXMLData(kCFAllocatorDefault, mimeFileData, kCFPropertyListImmutable, nullptr);
+ if (!propertyList) {
+ return nullptr;
+ }
+
+ AutoCFTypeObject propertyListAutorelease(propertyList);
+ if (::CFGetTypeID(propertyList) != ::CFDictionaryGetTypeID()) {
+ return nullptr;
+ }
+
+ CFTypeRef mimeTypes = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(propertyList), CFSTR("WebPluginMIMETypes"));
+ if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0) {
+ return nullptr;
+ }
+
+ return static_cast<CFDictionaryRef>(::CFRetain(mimeTypes));
+}
+
+static void ParsePlistPluginInfo(nsPluginInfo& info, CFBundleRef bundle)
+{
+ CFDictionaryRef mimeDict = ParsePlistForMIMETypesFilename(bundle);
+
+ if (!mimeDict) {
+ CFTypeRef mimeTypes = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypes"));
+ if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0)
+ return;
+ mimeDict = static_cast<CFDictionaryRef>(::CFRetain(mimeTypes));
+ }
+
+ AutoCFTypeObject mimeDictAutorelease(mimeDict);
+ int mimeDictKeyCount = ::CFDictionaryGetCount(mimeDict);
+
+ // Allocate memory for mime data
+ int mimeDataArraySize = mimeDictKeyCount * sizeof(char*);
+ info.fMimeTypeArray = static_cast<char**>(moz_xmalloc(mimeDataArraySize));
+ if (!info.fMimeTypeArray)
+ return;
+ memset(info.fMimeTypeArray, 0, mimeDataArraySize);
+ info.fExtensionArray = static_cast<char**>(moz_xmalloc(mimeDataArraySize));
+ if (!info.fExtensionArray)
+ return;
+ memset(info.fExtensionArray, 0, mimeDataArraySize);
+ info.fMimeDescriptionArray = static_cast<char**>(moz_xmalloc(mimeDataArraySize));
+ if (!info.fMimeDescriptionArray)
+ return;
+ memset(info.fMimeDescriptionArray, 0, mimeDataArraySize);
+
+ // Allocate memory for mime dictionary keys and values
+ mozilla::UniquePtr<CFTypeRef[]> keys(new CFTypeRef[mimeDictKeyCount]);
+ if (!keys)
+ return;
+ mozilla::UniquePtr<CFTypeRef[]> values(new CFTypeRef[mimeDictKeyCount]);
+ if (!values)
+ return;
+
+ info.fVariantCount = 0;
+
+ ::CFDictionaryGetKeysAndValues(mimeDict, keys.get(), values.get());
+ for (int i = 0; i < mimeDictKeyCount; i++) {
+ CFTypeRef mimeString = keys[i];
+ if (!mimeString || ::CFGetTypeID(mimeString) != ::CFStringGetTypeID()) {
+ continue;
+ }
+ CFTypeRef mimeDict = values[i];
+ if (mimeDict && ::CFGetTypeID(mimeDict) == ::CFDictionaryGetTypeID()) {
+ if (!MimeTypeEnabled(static_cast<CFDictionaryRef>(mimeDict))) {
+ continue;
+ }
+ info.fMimeTypeArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(mimeString));
+ if (!info.fMimeTypeArray[info.fVariantCount]) {
+ continue;
+ }
+ CFTypeRef extensions = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginExtensions"));
+ if (extensions && ::CFGetTypeID(extensions) == ::CFArrayGetTypeID()) {
+ int extensionCount = ::CFArrayGetCount(static_cast<CFArrayRef>(extensions));
+ CFMutableStringRef extensionList = ::CFStringCreateMutable(kCFAllocatorDefault, 0);
+ for (int j = 0; j < extensionCount; j++) {
+ CFTypeRef extension = ::CFArrayGetValueAtIndex(static_cast<CFArrayRef>(extensions), j);
+ if (extension && ::CFGetTypeID(extension) == ::CFStringGetTypeID()) {
+ if (j > 0)
+ ::CFStringAppend(extensionList, CFSTR(","));
+ ::CFStringAppend(static_cast<CFMutableStringRef>(extensionList), static_cast<CFStringRef>(extension));
+ }
+ }
+ info.fExtensionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(extensionList));
+ ::CFRelease(extensionList);
+ }
+ CFTypeRef description = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginTypeDescription"));
+ if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID())
+ info.fMimeDescriptionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description));
+ }
+ info.fVariantCount++;
+ }
+}
+
+nsPluginFile::nsPluginFile(nsIFile *spec)
+ : mPlugin(spec)
+{
+}
+
+nsPluginFile::~nsPluginFile() {}
+
+nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
+{
+ if (!mPlugin)
+ return NS_ERROR_NULL_POINTER;
+
+ // 64-bit NSPR does not (yet) support bundles. So in 64-bit builds we need
+ // (for now) to load the bundle's executable. However this can cause
+ // problems: CFBundleCreate() doesn't run the bundle's executable's
+ // initialization code, while NSAddImage() and dlopen() do run it. So using
+ // NSPR's dyld loading mechanisms here (NSAddImage() or dlopen()) can cause
+ // a bundle's initialization code to run earlier than expected, and lead to
+ // crashes. See bug 577967.
+#ifdef __LP64__
+ char executablePath[PATH_MAX];
+ executablePath[0] = '\0';
+ nsAutoCString bundlePath;
+ mPlugin->GetNativePath(bundlePath);
+ CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, bundlePath.get(),
+ kCFStringEncodingUTF8);
+ if (pathRef) {
+ CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef,
+ kCFURLPOSIXPathStyle,
+ true);
+ if (bundleURL) {
+ CFBundleRef bundle = ::CFBundleCreate(nullptr, bundleURL);
+ if (bundle) {
+ CFURLRef executableURL = ::CFBundleCopyExecutableURL(bundle);
+ if (executableURL) {
+ if (!::CFURLGetFileSystemRepresentation(executableURL, true, (UInt8*)&executablePath, PATH_MAX))
+ executablePath[0] = '\0';
+ ::CFRelease(executableURL);
+ }
+ ::CFRelease(bundle);
+ }
+ ::CFRelease(bundleURL);
+ }
+ ::CFRelease(pathRef);
+ }
+#else
+ nsAutoCString bundlePath;
+ mPlugin->GetNativePath(bundlePath);
+ const char *executablePath = bundlePath.get();
+#endif
+
+ *outLibrary = PR_LoadLibrary(executablePath);
+ pLibrary = *outLibrary;
+ if (!pLibrary) {
+ return NS_ERROR_FAILURE;
+ }
+#ifdef DEBUG
+ printf("[loaded plugin %s]\n", bundlePath.get());
+#endif
+ return NS_OK;
+}
+
+static char* p2cstrdup(StringPtr pstr)
+{
+ int len = pstr[0];
+ char* cstr = static_cast<char*>(moz_xmalloc(len + 1));
+ if (cstr) {
+ memmove(cstr, pstr + 1, len);
+ cstr[len] = '\0';
+ }
+ return cstr;
+}
+
+static char* GetNextPluginStringFromHandle(Handle h, short *index)
+{
+ char *ret = p2cstrdup((unsigned char*)(*h + *index));
+ *index += (ret ? strlen(ret) : 0) + 1;
+ return ret;
+}
+
+static bool IsCompatibleArch(nsIFile *file)
+{
+ CFURLRef pluginURL = nullptr;
+ if (NS_FAILED(toCFURLRef(file, pluginURL)))
+ return false;
+
+ bool isPluginFile = false;
+
+ CFBundleRef pluginBundle = ::CFBundleCreate(kCFAllocatorDefault, pluginURL);
+ if (pluginBundle) {
+ UInt32 packageType, packageCreator;
+ ::CFBundleGetPackageInfo(pluginBundle, &packageType, &packageCreator);
+ if (packageType == 'BRPL' || packageType == 'IEPL' || packageType == 'NSPL') {
+ // Get path to plugin as a C string.
+ char executablePath[PATH_MAX];
+ executablePath[0] = '\0';
+ if (!::CFURLGetFileSystemRepresentation(pluginURL, true, (UInt8*)&executablePath, PATH_MAX)) {
+ executablePath[0] = '\0';
+ }
+
+ uint32_t pluginLibArchitectures;
+ nsresult rv = mozilla::ipc::GeckoChildProcessHost::GetArchitecturesForBinary(executablePath, &pluginLibArchitectures);
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+
+ uint32_t supportedArchitectures =
+#ifdef __LP64__
+ mozilla::ipc::GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin);
+#else
+ base::GetCurrentProcessArchitecture();
+#endif
+
+ // Consider the plugin architecture valid if there is any overlap in the masks.
+ isPluginFile = !!(supportedArchitectures & pluginLibArchitectures);
+ }
+ ::CFRelease(pluginBundle);
+ }
+
+ ::CFRelease(pluginURL);
+ return isPluginFile;
+}
+
+/**
+ * Obtains all of the information currently available for this plugin.
+ */
+nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
+{
+ *outLibrary = nullptr;
+
+ nsresult rv = NS_OK;
+
+ if (!IsCompatibleArch(mPlugin)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // clear out the info, except for the first field.
+ memset(&info, 0, sizeof(info));
+
+ // Try to get a bundle reference.
+ nsAutoCString path;
+ if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
+ return rv;
+ CFBundleRef bundle = getPluginBundle(path.get());
+
+ // fill in full path
+ info.fFullPath = PL_strdup(path.get());
+
+ // fill in file name
+ nsAutoCString fileName;
+ if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
+ return rv;
+ info.fFileName = PL_strdup(fileName.get());
+
+ // Get fName
+ if (bundle) {
+ CFTypeRef name = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginName"));
+ if (name && ::CFGetTypeID(name) == ::CFStringGetTypeID())
+ info.fName = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(name));
+ }
+
+ // Get fDescription
+ if (bundle) {
+ CFTypeRef description = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginDescription"));
+ if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID())
+ info.fDescription = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description));
+ }
+
+ // Get fVersion
+ if (bundle) {
+ // Look for the release version first
+ CFTypeRef version = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString"));
+ if (!version) // try the build version
+ version = ::CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey);
+ if (version && ::CFGetTypeID(version) == ::CFStringGetTypeID())
+ info.fVersion = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(version));
+ }
+
+ // The last thing we need to do is get MIME data
+ // fVariantCount, fMimeTypeArray, fExtensionArray, fMimeDescriptionArray
+
+ // First look for data in a bundle plist
+ if (bundle) {
+ ParsePlistPluginInfo(info, bundle);
+ ::CFRelease(bundle);
+ if (info.fVariantCount > 0)
+ return NS_OK;
+ }
+
+ // Don't load "fbplugin" or any plugins whose name starts with "fbplugin_"
+ // (Facebook plugins) if we're running on OS X 10.10 (Yosemite) or later.
+ // A "fbplugin" file crashes on load, in the call to LoadPlugin() below.
+ // See bug 1086977.
+ if (nsCocoaFeatures::OnYosemiteOrLater()) {
+ if (fileName.EqualsLiteral("fbplugin") ||
+ StringBeginsWith(fileName, NS_LITERAL_CSTRING("fbplugin_"))) {
+ nsAutoCString msg;
+ msg.AppendPrintf("Preventing load of %s (see bug 1086977)",
+ fileName.get());
+ NS_WARNING(msg.get());
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ // It's possible that our plugin has 2 entry points that'll give us mime type
+ // info. Quicktime does this to get around the need of having admin rights to
+ // change mime info in the resource fork. We need to use this info instead of
+ // the resource. See bug 113464.
+
+ // Sadly we have to load the library for this to work.
+ rv = LoadPlugin(outLibrary);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // Try to get data from NP_GetMIMEDescription
+ if (pLibrary) {
+ NP_GETMIMEDESCRIPTION pfnGetMimeDesc = (NP_GETMIMEDESCRIPTION)PR_FindFunctionSymbol(pLibrary, NP_GETMIMEDESCRIPTION_NAME);
+ if (pfnGetMimeDesc)
+ ParsePluginMimeDescription(pfnGetMimeDesc(), info);
+ if (info.fVariantCount)
+ return NS_OK;
+ }
+
+ // We'll fill this in using BP_GetSupportedMIMETypes and/or resource fork data
+ BPSupportedMIMETypes mi = {kBPSupportedMIMETypesStructVers_1, nullptr, nullptr};
+
+ // Try to get data from BP_GetSupportedMIMETypes
+ if (pLibrary) {
+ BP_GETSUPPORTEDMIMETYPES pfnMime = (BP_GETSUPPORTEDMIMETYPES)PR_FindFunctionSymbol(pLibrary, "BP_GetSupportedMIMETypes");
+ if (pfnMime && noErr == pfnMime(&mi, 0) && mi.typeStrings) {
+ info.fVariantCount = (**(short**)mi.typeStrings) / 2;
+ ::HLock(mi.typeStrings);
+ if (mi.infoStrings) // it's possible some plugins have infoStrings missing
+ ::HLock(mi.infoStrings);
+ }
+ }
+
+ // Fill in the info struct based on the data in the BPSupportedMIMETypes struct
+ int variantCount = info.fVariantCount;
+ info.fMimeTypeArray = static_cast<char**>(moz_xmalloc(variantCount * sizeof(char*)));
+ if (!info.fMimeTypeArray)
+ return NS_ERROR_OUT_OF_MEMORY;
+ info.fExtensionArray = static_cast<char**>(moz_xmalloc(variantCount * sizeof(char*)));
+ if (!info.fExtensionArray)
+ return NS_ERROR_OUT_OF_MEMORY;
+ if (mi.infoStrings) {
+ info.fMimeDescriptionArray = static_cast<char**>(moz_xmalloc(variantCount * sizeof(char*)));
+ if (!info.fMimeDescriptionArray)
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ short mimeIndex = 2;
+ short descriptionIndex = 2;
+ for (int i = 0; i < variantCount; i++) {
+ info.fMimeTypeArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex);
+ info.fExtensionArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex);
+ if (mi.infoStrings)
+ info.fMimeDescriptionArray[i] = GetNextPluginStringFromHandle(mi.infoStrings, &descriptionIndex);
+ }
+
+ ::HUnlock(mi.typeStrings);
+ ::DisposeHandle(mi.typeStrings);
+ if (mi.infoStrings) {
+ ::HUnlock(mi.infoStrings);
+ ::DisposeHandle(mi.infoStrings);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info)
+{
+ free(info.fName);
+ free(info.fDescription);
+ int variantCount = info.fVariantCount;
+ for (int i = 0; i < variantCount; i++) {
+ free(info.fMimeTypeArray[i]);
+ free(info.fExtensionArray[i]);
+ free(info.fMimeDescriptionArray[i]);
+ }
+ free(info.fMimeTypeArray);
+ free(info.fMimeDescriptionArray);
+ free(info.fExtensionArray);
+ free(info.fFileName);
+ free(info.fFullPath);
+ free(info.fVersion);
+
+ return NS_OK;
+}