dom/plugins/base/nsPluginsDirDarwin.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/plugins/base/nsPluginsDirDarwin.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,555 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +  nsPluginsDirDarwin.cpp
    1.11 +  
    1.12 +  Mac OS X implementation of the nsPluginsDir/nsPluginsFile classes.
    1.13 +  
    1.14 +  by Patrick C. Beard.
    1.15 + */
    1.16 +
    1.17 +#include "GeckoChildProcessHost.h"
    1.18 +#include "base/process_util.h"
    1.19 +
    1.20 +#include "prlink.h"
    1.21 +#include "prnetdb.h"
    1.22 +#include "nsXPCOM.h"
    1.23 +
    1.24 +#include "nsPluginsDir.h"
    1.25 +#include "nsNPAPIPlugin.h"
    1.26 +#include "nsPluginsDirUtils.h"
    1.27 +
    1.28 +#include "nsILocalFileMac.h"
    1.29 +
    1.30 +#include <string.h>
    1.31 +#include <stdio.h>
    1.32 +#include <unistd.h>
    1.33 +#include <fcntl.h>
    1.34 +
    1.35 +#include <Carbon/Carbon.h>
    1.36 +#include <CoreServices/CoreServices.h>
    1.37 +#include <mach-o/loader.h>
    1.38 +#include <mach-o/fat.h>
    1.39 +
    1.40 +typedef NS_NPAPIPLUGIN_CALLBACK(const char *, NP_GETMIMEDESCRIPTION) ();
    1.41 +typedef NS_NPAPIPLUGIN_CALLBACK(OSErr, BP_GETSUPPORTEDMIMETYPES) (BPSupportedMIMETypes *mimeInfo, UInt32 flags);
    1.42 +
    1.43 +
    1.44 +/*
    1.45 +** Returns a CFBundleRef if the path refers to a Mac OS X bundle directory.
    1.46 +** The caller is responsible for calling CFRelease() to deallocate.
    1.47 +*/
    1.48 +static CFBundleRef getPluginBundle(const char* path)
    1.49 +{
    1.50 +  CFBundleRef bundle = nullptr;
    1.51 +  CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, path,
    1.52 +                                                    kCFStringEncodingUTF8);
    1.53 +  if (pathRef) {
    1.54 +    CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef,
    1.55 +                                                         kCFURLPOSIXPathStyle,
    1.56 +                                                         true);
    1.57 +    if (bundleURL) {
    1.58 +      bundle = ::CFBundleCreate(nullptr, bundleURL);
    1.59 +      ::CFRelease(bundleURL);
    1.60 +    }
    1.61 +    ::CFRelease(pathRef);
    1.62 +  }
    1.63 +  return bundle;
    1.64 +}
    1.65 +
    1.66 +static nsresult toCFURLRef(nsIFile* file, CFURLRef& outURL)
    1.67 +{
    1.68 +  nsCOMPtr<nsILocalFileMac> lfm = do_QueryInterface(file);
    1.69 +  if (!lfm)
    1.70 +    return NS_ERROR_FAILURE;
    1.71 +  CFURLRef url;
    1.72 +  nsresult rv = lfm->GetCFURL(&url);
    1.73 +  if (NS_SUCCEEDED(rv))
    1.74 +    outURL = url;
    1.75 +  
    1.76 +  return rv;
    1.77 +}
    1.78 +
    1.79 +bool nsPluginsDir::IsPluginFile(nsIFile* file)
    1.80 +{
    1.81 +  nsCString fileName;
    1.82 +  file->GetNativeLeafName(fileName);
    1.83 +  /*
    1.84 +   * Don't load the VDP fake plugin, to avoid tripping a bad bug in OS X
    1.85 +   * 10.5.3 (see bug 436575).
    1.86 +   */
    1.87 +  if (!strcmp(fileName.get(), "VerifiedDownloadPlugin.plugin")) {
    1.88 +    NS_WARNING("Preventing load of VerifiedDownloadPlugin.plugin (see bug 436575)");
    1.89 +    return false;
    1.90 +  }
    1.91 +  return true;
    1.92 +}
    1.93 +
    1.94 +// Caller is responsible for freeing returned buffer.
    1.95 +static char* CFStringRefToUTF8Buffer(CFStringRef cfString)
    1.96 +{
    1.97 +  const char* buffer = ::CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8);
    1.98 +  if (buffer) {
    1.99 +    return PL_strdup(buffer);
   1.100 +  }
   1.101 +
   1.102 +  int bufferLength =
   1.103 +    ::CFStringGetMaximumSizeForEncoding(::CFStringGetLength(cfString),
   1.104 +                                        kCFStringEncodingUTF8) + 1;
   1.105 +  char* newBuffer = static_cast<char*>(NS_Alloc(bufferLength));
   1.106 +  if (!newBuffer) {
   1.107 +    return nullptr;
   1.108 +  }
   1.109 +
   1.110 +  if (!::CFStringGetCString(cfString, newBuffer, bufferLength,
   1.111 +                            kCFStringEncodingUTF8)) {
   1.112 +    NS_Free(newBuffer);
   1.113 +    return nullptr;
   1.114 +  }
   1.115 +
   1.116 +  newBuffer = static_cast<char*>(NS_Realloc(newBuffer,
   1.117 +                                            strlen(newBuffer) + 1));
   1.118 +  return newBuffer;
   1.119 +}
   1.120 +
   1.121 +class AutoCFTypeObject {
   1.122 +public:
   1.123 +  AutoCFTypeObject(CFTypeRef object)
   1.124 +  {
   1.125 +    mObject = object;
   1.126 +  }
   1.127 +  ~AutoCFTypeObject()
   1.128 +  {
   1.129 +    ::CFRelease(mObject);
   1.130 +  }
   1.131 +private:
   1.132 +  CFTypeRef mObject;
   1.133 +};
   1.134 +
   1.135 +static Boolean MimeTypeEnabled(CFDictionaryRef mimeDict) {
   1.136 +  if (!mimeDict) {
   1.137 +    return true;
   1.138 +  }
   1.139 +  
   1.140 +  CFTypeRef value;
   1.141 +  if (::CFDictionaryGetValueIfPresent(mimeDict, CFSTR("WebPluginTypeEnabled"), &value)) {
   1.142 +    if (value && ::CFGetTypeID(value) == ::CFBooleanGetTypeID()) {
   1.143 +      return ::CFBooleanGetValue(static_cast<CFBooleanRef>(value));
   1.144 +    }
   1.145 +  }
   1.146 +  return true;
   1.147 +}
   1.148 +
   1.149 +static CFDictionaryRef ParsePlistForMIMETypesFilename(CFBundleRef bundle)
   1.150 +{
   1.151 +  CFTypeRef mimeFileName = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypesFilename"));
   1.152 +  if (!mimeFileName || ::CFGetTypeID(mimeFileName) != ::CFStringGetTypeID()) {
   1.153 +    return nullptr;
   1.154 +  }
   1.155 +  
   1.156 +  FSRef homeDir;
   1.157 +  if (::FSFindFolder(kUserDomain, kCurrentUserFolderType, kDontCreateFolder, &homeDir) != noErr) {
   1.158 +    return nullptr;
   1.159 +  }
   1.160 +  
   1.161 +  CFURLRef userDirURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, &homeDir);
   1.162 +  if (!userDirURL) {
   1.163 +    return nullptr;
   1.164 +  }
   1.165 +  
   1.166 +  AutoCFTypeObject userDirURLAutorelease(userDirURL);
   1.167 +  CFStringRef mimeFilePath = ::CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("Library/Preferences/%@"), static_cast<CFStringRef>(mimeFileName));
   1.168 +  if (!mimeFilePath) {
   1.169 +    return nullptr;
   1.170 +  }
   1.171 +  
   1.172 +  AutoCFTypeObject mimeFilePathAutorelease(mimeFilePath);
   1.173 +  CFURLRef mimeFileURL = ::CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, mimeFilePath, kCFURLPOSIXPathStyle, false, userDirURL);
   1.174 +  if (!mimeFileURL) {
   1.175 +    return nullptr;
   1.176 +  }
   1.177 +  
   1.178 +  AutoCFTypeObject mimeFileURLAutorelease(mimeFileURL);
   1.179 +  SInt32 errorCode = 0;
   1.180 +  CFDataRef mimeFileData = nullptr;
   1.181 +  Boolean result = ::CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, mimeFileURL, &mimeFileData, nullptr, nullptr, &errorCode);
   1.182 +  if (!result) {
   1.183 +    return nullptr;
   1.184 +  }
   1.185 +  
   1.186 +  AutoCFTypeObject mimeFileDataAutorelease(mimeFileData);
   1.187 +  if (errorCode != 0) {
   1.188 +    return nullptr;
   1.189 +  }
   1.190 +  
   1.191 +  CFPropertyListRef propertyList = ::CFPropertyListCreateFromXMLData(kCFAllocatorDefault, mimeFileData, kCFPropertyListImmutable, nullptr);
   1.192 +  if (!propertyList) {
   1.193 +    return nullptr;
   1.194 +  }
   1.195 +  
   1.196 +  AutoCFTypeObject propertyListAutorelease(propertyList);
   1.197 +  if (::CFGetTypeID(propertyList) != ::CFDictionaryGetTypeID()) {
   1.198 +    return nullptr;
   1.199 +  }
   1.200 +
   1.201 +  CFTypeRef mimeTypes = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(propertyList), CFSTR("WebPluginMIMETypes"));
   1.202 +  if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0) {
   1.203 +    return nullptr;
   1.204 +  }
   1.205 +  
   1.206 +  return static_cast<CFDictionaryRef>(::CFRetain(mimeTypes));
   1.207 +}
   1.208 +
   1.209 +static void ParsePlistPluginInfo(nsPluginInfo& info, CFBundleRef bundle)
   1.210 +{
   1.211 +  CFDictionaryRef mimeDict = ParsePlistForMIMETypesFilename(bundle);
   1.212 +  
   1.213 +  if (!mimeDict) {
   1.214 +    CFTypeRef mimeTypes = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypes"));
   1.215 +    if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0)
   1.216 +      return;
   1.217 +    mimeDict = static_cast<CFDictionaryRef>(::CFRetain(mimeTypes));
   1.218 +  }
   1.219 +  
   1.220 +  AutoCFTypeObject mimeDictAutorelease(mimeDict);
   1.221 +  int mimeDictKeyCount = ::CFDictionaryGetCount(mimeDict);
   1.222 +
   1.223 +  // Allocate memory for mime data
   1.224 +  int mimeDataArraySize = mimeDictKeyCount * sizeof(char*);
   1.225 +  info.fMimeTypeArray = static_cast<char**>(NS_Alloc(mimeDataArraySize));
   1.226 +  if (!info.fMimeTypeArray)
   1.227 +    return;
   1.228 +  memset(info.fMimeTypeArray, 0, mimeDataArraySize);
   1.229 +  info.fExtensionArray = static_cast<char**>(NS_Alloc(mimeDataArraySize));
   1.230 +  if (!info.fExtensionArray)
   1.231 +    return;
   1.232 +  memset(info.fExtensionArray, 0, mimeDataArraySize);
   1.233 +  info.fMimeDescriptionArray = static_cast<char**>(NS_Alloc(mimeDataArraySize));
   1.234 +  if (!info.fMimeDescriptionArray)
   1.235 +    return;
   1.236 +  memset(info.fMimeDescriptionArray, 0, mimeDataArraySize);
   1.237 +
   1.238 +  // Allocate memory for mime dictionary keys and values
   1.239 +  nsAutoArrayPtr<CFTypeRef> keys(new CFTypeRef[mimeDictKeyCount]);
   1.240 +  if (!keys)
   1.241 +    return;
   1.242 +  nsAutoArrayPtr<CFTypeRef> values(new CFTypeRef[mimeDictKeyCount]);
   1.243 +  if (!values)
   1.244 +    return;
   1.245 +  
   1.246 +  info.fVariantCount = 0;
   1.247 +
   1.248 +  ::CFDictionaryGetKeysAndValues(mimeDict, keys, values);
   1.249 +  for (int i = 0; i < mimeDictKeyCount; i++) {
   1.250 +    CFTypeRef mimeString = keys[i];
   1.251 +    if (!mimeString || ::CFGetTypeID(mimeString) != ::CFStringGetTypeID()) {
   1.252 +      continue;
   1.253 +    }
   1.254 +    CFTypeRef mimeDict = values[i];
   1.255 +    if (mimeDict && ::CFGetTypeID(mimeDict) == ::CFDictionaryGetTypeID()) {
   1.256 +      if (!MimeTypeEnabled(static_cast<CFDictionaryRef>(mimeDict))) {
   1.257 +        continue;
   1.258 +      }
   1.259 +      info.fMimeTypeArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(mimeString));
   1.260 +      if (!info.fMimeTypeArray[info.fVariantCount]) {
   1.261 +        continue;
   1.262 +      }
   1.263 +      CFTypeRef extensions = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginExtensions"));
   1.264 +      if (extensions && ::CFGetTypeID(extensions) == ::CFArrayGetTypeID()) {
   1.265 +        int extensionCount = ::CFArrayGetCount(static_cast<CFArrayRef>(extensions));
   1.266 +        CFMutableStringRef extensionList = ::CFStringCreateMutable(kCFAllocatorDefault, 0);
   1.267 +        for (int j = 0; j < extensionCount; j++) {
   1.268 +          CFTypeRef extension = ::CFArrayGetValueAtIndex(static_cast<CFArrayRef>(extensions), j);
   1.269 +          if (extension && ::CFGetTypeID(extension) == ::CFStringGetTypeID()) {
   1.270 +            if (j > 0)
   1.271 +              ::CFStringAppend(extensionList, CFSTR(","));
   1.272 +            ::CFStringAppend(static_cast<CFMutableStringRef>(extensionList), static_cast<CFStringRef>(extension));
   1.273 +          }
   1.274 +        }
   1.275 +        info.fExtensionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(extensionList));
   1.276 +        ::CFRelease(extensionList);
   1.277 +      }
   1.278 +      CFTypeRef description = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginTypeDescription"));
   1.279 +      if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID())
   1.280 +        info.fMimeDescriptionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description));
   1.281 +    }
   1.282 +    info.fVariantCount++;
   1.283 +  }
   1.284 +}
   1.285 +
   1.286 +nsPluginFile::nsPluginFile(nsIFile *spec)
   1.287 +    : mPlugin(spec)
   1.288 +{
   1.289 +}
   1.290 +
   1.291 +nsPluginFile::~nsPluginFile() {}
   1.292 +
   1.293 +nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
   1.294 +{
   1.295 +  if (!mPlugin)
   1.296 +    return NS_ERROR_NULL_POINTER;
   1.297 +
   1.298 +  // 64-bit NSPR does not (yet) support bundles.  So in 64-bit builds we need
   1.299 +  // (for now) to load the bundle's executable.  However this can cause
   1.300 +  // problems:  CFBundleCreate() doesn't run the bundle's executable's
   1.301 +  // initialization code, while NSAddImage() and dlopen() do run it.  So using
   1.302 +  // NSPR's dyld loading mechanisms here (NSAddImage() or dlopen()) can cause
   1.303 +  // a bundle's initialization code to run earlier than expected, and lead to
   1.304 +  // crashes.  See bug 577967.
   1.305 +#ifdef __LP64__
   1.306 +  char executablePath[PATH_MAX];
   1.307 +  executablePath[0] = '\0';
   1.308 +  nsAutoCString bundlePath;
   1.309 +  mPlugin->GetNativePath(bundlePath);
   1.310 +  CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, bundlePath.get(),
   1.311 +                                                    kCFStringEncodingUTF8);
   1.312 +  if (pathRef) {
   1.313 +    CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef,
   1.314 +                                                         kCFURLPOSIXPathStyle,
   1.315 +                                                         true);
   1.316 +    if (bundleURL) {
   1.317 +      CFBundleRef bundle = ::CFBundleCreate(nullptr, bundleURL);
   1.318 +      if (bundle) {
   1.319 +        CFURLRef executableURL = ::CFBundleCopyExecutableURL(bundle);
   1.320 +        if (executableURL) {
   1.321 +          if (!::CFURLGetFileSystemRepresentation(executableURL, true, (UInt8*)&executablePath, PATH_MAX))
   1.322 +            executablePath[0] = '\0';
   1.323 +          ::CFRelease(executableURL);
   1.324 +        }
   1.325 +        ::CFRelease(bundle);
   1.326 +      }
   1.327 +      ::CFRelease(bundleURL);
   1.328 +    }
   1.329 +    ::CFRelease(pathRef); 
   1.330 +  }
   1.331 +#else
   1.332 +  nsAutoCString bundlePath;
   1.333 +  mPlugin->GetNativePath(bundlePath);
   1.334 +  const char *executablePath = bundlePath.get();
   1.335 +#endif
   1.336 +
   1.337 +  *outLibrary = PR_LoadLibrary(executablePath);
   1.338 +  pLibrary = *outLibrary;
   1.339 +  if (!pLibrary) {
   1.340 +    return NS_ERROR_FAILURE;
   1.341 +  }
   1.342 +#ifdef DEBUG
   1.343 +  printf("[loaded plugin %s]\n", bundlePath.get());
   1.344 +#endif
   1.345 +  return NS_OK;
   1.346 +}
   1.347 +
   1.348 +static char* p2cstrdup(StringPtr pstr)
   1.349 +{
   1.350 +  int len = pstr[0];
   1.351 +  char* cstr = static_cast<char*>(NS_Alloc(len + 1));
   1.352 +  if (cstr) {
   1.353 +    memmove(cstr, pstr + 1, len);
   1.354 +    cstr[len] = '\0';
   1.355 +  }
   1.356 +  return cstr;
   1.357 +}
   1.358 +
   1.359 +static char* GetNextPluginStringFromHandle(Handle h, short *index)
   1.360 +{
   1.361 +  char *ret = p2cstrdup((unsigned char*)(*h + *index));
   1.362 +  *index += (ret ? strlen(ret) : 0) + 1;
   1.363 +  return ret;
   1.364 +}
   1.365 +
   1.366 +static bool IsCompatibleArch(nsIFile *file)
   1.367 +{
   1.368 +  CFURLRef pluginURL = nullptr;
   1.369 +  if (NS_FAILED(toCFURLRef(file, pluginURL)))
   1.370 +    return false;
   1.371 +  
   1.372 +  bool isPluginFile = false;
   1.373 +
   1.374 +  CFBundleRef pluginBundle = ::CFBundleCreate(kCFAllocatorDefault, pluginURL);
   1.375 +  if (pluginBundle) {
   1.376 +    UInt32 packageType, packageCreator;
   1.377 +    ::CFBundleGetPackageInfo(pluginBundle, &packageType, &packageCreator);
   1.378 +    if (packageType == 'BRPL' || packageType == 'IEPL' || packageType == 'NSPL') {
   1.379 +      // Get path to plugin as a C string.
   1.380 +      char executablePath[PATH_MAX];
   1.381 +      executablePath[0] = '\0';
   1.382 +      if (!::CFURLGetFileSystemRepresentation(pluginURL, true, (UInt8*)&executablePath, PATH_MAX)) {
   1.383 +        executablePath[0] = '\0';
   1.384 +      }
   1.385 +
   1.386 +      uint32_t pluginLibArchitectures;
   1.387 +      nsresult rv = mozilla::ipc::GeckoChildProcessHost::GetArchitecturesForBinary(executablePath, &pluginLibArchitectures);
   1.388 +      if (NS_FAILED(rv)) {
   1.389 +        return false;
   1.390 +      }
   1.391 +
   1.392 +      uint32_t supportedArchitectures =
   1.393 +#ifdef __LP64__
   1.394 +          mozilla::ipc::GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin);
   1.395 +#else
   1.396 +          base::GetCurrentProcessArchitecture();
   1.397 +#endif
   1.398 +
   1.399 +      // Consider the plugin architecture valid if there is any overlap in the masks.
   1.400 +      isPluginFile = !!(supportedArchitectures & pluginLibArchitectures);
   1.401 +    }
   1.402 +    ::CFRelease(pluginBundle);
   1.403 +  }
   1.404 +
   1.405 +  ::CFRelease(pluginURL);
   1.406 +  return isPluginFile;
   1.407 +}
   1.408 +
   1.409 +/**
   1.410 + * Obtains all of the information currently available for this plugin.
   1.411 + */
   1.412 +nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
   1.413 +{
   1.414 +  *outLibrary = nullptr;
   1.415 +
   1.416 +  nsresult rv = NS_OK;
   1.417 +
   1.418 +  if (!IsCompatibleArch(mPlugin)) {
   1.419 +      return NS_ERROR_FAILURE;
   1.420 +  }
   1.421 +
   1.422 +  // clear out the info, except for the first field.
   1.423 +  memset(&info, 0, sizeof(info));
   1.424 +
   1.425 +  // Try to get a bundle reference.
   1.426 +  nsAutoCString path;
   1.427 +  if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
   1.428 +    return rv;
   1.429 +  CFBundleRef bundle = getPluginBundle(path.get());
   1.430 +
   1.431 +  // fill in full path
   1.432 +  info.fFullPath = PL_strdup(path.get());
   1.433 +
   1.434 +  // fill in file name
   1.435 +  nsAutoCString fileName;
   1.436 +  if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
   1.437 +    return rv;
   1.438 +  info.fFileName = PL_strdup(fileName.get());
   1.439 +
   1.440 +  // Get fName
   1.441 +  if (bundle) {
   1.442 +    CFTypeRef name = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginName"));
   1.443 +    if (name && ::CFGetTypeID(name) == ::CFStringGetTypeID())
   1.444 +      info.fName = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(name));
   1.445 +  }
   1.446 +
   1.447 +  // Get fDescription
   1.448 +  if (bundle) {
   1.449 +    CFTypeRef description = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginDescription"));
   1.450 +    if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID())
   1.451 +      info.fDescription = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description));
   1.452 +  }
   1.453 +
   1.454 +  // Get fVersion
   1.455 +  if (bundle) {
   1.456 +    // Look for the release version first
   1.457 +    CFTypeRef version = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString"));
   1.458 +    if (!version) // try the build version
   1.459 +      version = ::CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey);
   1.460 +    if (version && ::CFGetTypeID(version) == ::CFStringGetTypeID())
   1.461 +      info.fVersion = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(version));
   1.462 +  }
   1.463 +
   1.464 +  // The last thing we need to do is get MIME data
   1.465 +  // fVariantCount, fMimeTypeArray, fExtensionArray, fMimeDescriptionArray
   1.466 +
   1.467 +  // First look for data in a bundle plist
   1.468 +  if (bundle) {
   1.469 +    ParsePlistPluginInfo(info, bundle);
   1.470 +    ::CFRelease(bundle);
   1.471 +    if (info.fVariantCount > 0)
   1.472 +      return NS_OK;
   1.473 +  }
   1.474 +
   1.475 +  // It's possible that our plugin has 2 entry points that'll give us mime type
   1.476 +  // info. Quicktime does this to get around the need of having admin rights to
   1.477 +  // change mime info in the resource fork. We need to use this info instead of
   1.478 +  // the resource. See bug 113464.
   1.479 +
   1.480 +  // Sadly we have to load the library for this to work.
   1.481 +  rv = LoadPlugin(outLibrary);
   1.482 +  if (NS_FAILED(rv))
   1.483 +    return rv;
   1.484 +
   1.485 +  // Try to get data from NP_GetMIMEDescription
   1.486 +  if (pLibrary) {
   1.487 +    NP_GETMIMEDESCRIPTION pfnGetMimeDesc = (NP_GETMIMEDESCRIPTION)PR_FindFunctionSymbol(pLibrary, NP_GETMIMEDESCRIPTION_NAME); 
   1.488 +    if (pfnGetMimeDesc)
   1.489 +      ParsePluginMimeDescription(pfnGetMimeDesc(), info);
   1.490 +    if (info.fVariantCount)
   1.491 +      return NS_OK;
   1.492 +  }
   1.493 +
   1.494 +  // We'll fill this in using BP_GetSupportedMIMETypes and/or resource fork data
   1.495 +  BPSupportedMIMETypes mi = {kBPSupportedMIMETypesStructVers_1, nullptr, nullptr};
   1.496 +
   1.497 +  // Try to get data from BP_GetSupportedMIMETypes
   1.498 +  if (pLibrary) {
   1.499 +    BP_GETSUPPORTEDMIMETYPES pfnMime = (BP_GETSUPPORTEDMIMETYPES)PR_FindFunctionSymbol(pLibrary, "BP_GetSupportedMIMETypes");
   1.500 +    if (pfnMime && noErr == pfnMime(&mi, 0) && mi.typeStrings) {
   1.501 +      info.fVariantCount = (**(short**)mi.typeStrings) / 2;
   1.502 +      ::HLock(mi.typeStrings);
   1.503 +      if (mi.infoStrings)  // it's possible some plugins have infoStrings missing
   1.504 +        ::HLock(mi.infoStrings);
   1.505 +    }
   1.506 +  }
   1.507 +
   1.508 +  // Fill in the info struct based on the data in the BPSupportedMIMETypes struct
   1.509 +  int variantCount = info.fVariantCount;
   1.510 +  info.fMimeTypeArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*)));
   1.511 +  if (!info.fMimeTypeArray)
   1.512 +    return NS_ERROR_OUT_OF_MEMORY;
   1.513 +  info.fExtensionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*)));
   1.514 +  if (!info.fExtensionArray)
   1.515 +    return NS_ERROR_OUT_OF_MEMORY;
   1.516 +  if (mi.infoStrings) {
   1.517 +    info.fMimeDescriptionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*)));
   1.518 +    if (!info.fMimeDescriptionArray)
   1.519 +      return NS_ERROR_OUT_OF_MEMORY;
   1.520 +  }
   1.521 +  short mimeIndex = 2;
   1.522 +  short descriptionIndex = 2;
   1.523 +  for (int i = 0; i < variantCount; i++) {
   1.524 +    info.fMimeTypeArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex);
   1.525 +    info.fExtensionArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex);
   1.526 +    if (mi.infoStrings)
   1.527 +      info.fMimeDescriptionArray[i] = GetNextPluginStringFromHandle(mi.infoStrings, &descriptionIndex);
   1.528 +  }
   1.529 +
   1.530 +  ::HUnlock(mi.typeStrings);
   1.531 +  ::DisposeHandle(mi.typeStrings);
   1.532 +  if (mi.infoStrings) {
   1.533 +    ::HUnlock(mi.infoStrings);
   1.534 +    ::DisposeHandle(mi.infoStrings);
   1.535 +  }
   1.536 +
   1.537 +  return NS_OK;
   1.538 +}
   1.539 +
   1.540 +nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info)
   1.541 +{
   1.542 +  NS_Free(info.fName);
   1.543 +  NS_Free(info.fDescription);
   1.544 +  int variantCount = info.fVariantCount;
   1.545 +  for (int i = 0; i < variantCount; i++) {
   1.546 +    NS_Free(info.fMimeTypeArray[i]);
   1.547 +    NS_Free(info.fExtensionArray[i]);
   1.548 +    NS_Free(info.fMimeDescriptionArray[i]);
   1.549 +  }
   1.550 +  NS_Free(info.fMimeTypeArray);
   1.551 +  NS_Free(info.fMimeDescriptionArray);
   1.552 +  NS_Free(info.fExtensionArray);
   1.553 +  NS_Free(info.fFileName);
   1.554 +  NS_Free(info.fFullPath);
   1.555 +  NS_Free(info.fVersion);
   1.556 +
   1.557 +  return NS_OK;
   1.558 +}

mercurial