dom/plugins/base/nsPluginsDirDarwin.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 nsPluginsDirDarwin.cpp
michael@0 8
michael@0 9 Mac OS X implementation of the nsPluginsDir/nsPluginsFile classes.
michael@0 10
michael@0 11 by Patrick C. Beard.
michael@0 12 */
michael@0 13
michael@0 14 #include "GeckoChildProcessHost.h"
michael@0 15 #include "base/process_util.h"
michael@0 16
michael@0 17 #include "prlink.h"
michael@0 18 #include "prnetdb.h"
michael@0 19 #include "nsXPCOM.h"
michael@0 20
michael@0 21 #include "nsPluginsDir.h"
michael@0 22 #include "nsNPAPIPlugin.h"
michael@0 23 #include "nsPluginsDirUtils.h"
michael@0 24
michael@0 25 #include "nsILocalFileMac.h"
michael@0 26
michael@0 27 #include <string.h>
michael@0 28 #include <stdio.h>
michael@0 29 #include <unistd.h>
michael@0 30 #include <fcntl.h>
michael@0 31
michael@0 32 #include <Carbon/Carbon.h>
michael@0 33 #include <CoreServices/CoreServices.h>
michael@0 34 #include <mach-o/loader.h>
michael@0 35 #include <mach-o/fat.h>
michael@0 36
michael@0 37 typedef NS_NPAPIPLUGIN_CALLBACK(const char *, NP_GETMIMEDESCRIPTION) ();
michael@0 38 typedef NS_NPAPIPLUGIN_CALLBACK(OSErr, BP_GETSUPPORTEDMIMETYPES) (BPSupportedMIMETypes *mimeInfo, UInt32 flags);
michael@0 39
michael@0 40
michael@0 41 /*
michael@0 42 ** Returns a CFBundleRef if the path refers to a Mac OS X bundle directory.
michael@0 43 ** The caller is responsible for calling CFRelease() to deallocate.
michael@0 44 */
michael@0 45 static CFBundleRef getPluginBundle(const char* path)
michael@0 46 {
michael@0 47 CFBundleRef bundle = nullptr;
michael@0 48 CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, path,
michael@0 49 kCFStringEncodingUTF8);
michael@0 50 if (pathRef) {
michael@0 51 CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef,
michael@0 52 kCFURLPOSIXPathStyle,
michael@0 53 true);
michael@0 54 if (bundleURL) {
michael@0 55 bundle = ::CFBundleCreate(nullptr, bundleURL);
michael@0 56 ::CFRelease(bundleURL);
michael@0 57 }
michael@0 58 ::CFRelease(pathRef);
michael@0 59 }
michael@0 60 return bundle;
michael@0 61 }
michael@0 62
michael@0 63 static nsresult toCFURLRef(nsIFile* file, CFURLRef& outURL)
michael@0 64 {
michael@0 65 nsCOMPtr<nsILocalFileMac> lfm = do_QueryInterface(file);
michael@0 66 if (!lfm)
michael@0 67 return NS_ERROR_FAILURE;
michael@0 68 CFURLRef url;
michael@0 69 nsresult rv = lfm->GetCFURL(&url);
michael@0 70 if (NS_SUCCEEDED(rv))
michael@0 71 outURL = url;
michael@0 72
michael@0 73 return rv;
michael@0 74 }
michael@0 75
michael@0 76 bool nsPluginsDir::IsPluginFile(nsIFile* file)
michael@0 77 {
michael@0 78 nsCString fileName;
michael@0 79 file->GetNativeLeafName(fileName);
michael@0 80 /*
michael@0 81 * Don't load the VDP fake plugin, to avoid tripping a bad bug in OS X
michael@0 82 * 10.5.3 (see bug 436575).
michael@0 83 */
michael@0 84 if (!strcmp(fileName.get(), "VerifiedDownloadPlugin.plugin")) {
michael@0 85 NS_WARNING("Preventing load of VerifiedDownloadPlugin.plugin (see bug 436575)");
michael@0 86 return false;
michael@0 87 }
michael@0 88 return true;
michael@0 89 }
michael@0 90
michael@0 91 // Caller is responsible for freeing returned buffer.
michael@0 92 static char* CFStringRefToUTF8Buffer(CFStringRef cfString)
michael@0 93 {
michael@0 94 const char* buffer = ::CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8);
michael@0 95 if (buffer) {
michael@0 96 return PL_strdup(buffer);
michael@0 97 }
michael@0 98
michael@0 99 int bufferLength =
michael@0 100 ::CFStringGetMaximumSizeForEncoding(::CFStringGetLength(cfString),
michael@0 101 kCFStringEncodingUTF8) + 1;
michael@0 102 char* newBuffer = static_cast<char*>(NS_Alloc(bufferLength));
michael@0 103 if (!newBuffer) {
michael@0 104 return nullptr;
michael@0 105 }
michael@0 106
michael@0 107 if (!::CFStringGetCString(cfString, newBuffer, bufferLength,
michael@0 108 kCFStringEncodingUTF8)) {
michael@0 109 NS_Free(newBuffer);
michael@0 110 return nullptr;
michael@0 111 }
michael@0 112
michael@0 113 newBuffer = static_cast<char*>(NS_Realloc(newBuffer,
michael@0 114 strlen(newBuffer) + 1));
michael@0 115 return newBuffer;
michael@0 116 }
michael@0 117
michael@0 118 class AutoCFTypeObject {
michael@0 119 public:
michael@0 120 AutoCFTypeObject(CFTypeRef object)
michael@0 121 {
michael@0 122 mObject = object;
michael@0 123 }
michael@0 124 ~AutoCFTypeObject()
michael@0 125 {
michael@0 126 ::CFRelease(mObject);
michael@0 127 }
michael@0 128 private:
michael@0 129 CFTypeRef mObject;
michael@0 130 };
michael@0 131
michael@0 132 static Boolean MimeTypeEnabled(CFDictionaryRef mimeDict) {
michael@0 133 if (!mimeDict) {
michael@0 134 return true;
michael@0 135 }
michael@0 136
michael@0 137 CFTypeRef value;
michael@0 138 if (::CFDictionaryGetValueIfPresent(mimeDict, CFSTR("WebPluginTypeEnabled"), &value)) {
michael@0 139 if (value && ::CFGetTypeID(value) == ::CFBooleanGetTypeID()) {
michael@0 140 return ::CFBooleanGetValue(static_cast<CFBooleanRef>(value));
michael@0 141 }
michael@0 142 }
michael@0 143 return true;
michael@0 144 }
michael@0 145
michael@0 146 static CFDictionaryRef ParsePlistForMIMETypesFilename(CFBundleRef bundle)
michael@0 147 {
michael@0 148 CFTypeRef mimeFileName = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypesFilename"));
michael@0 149 if (!mimeFileName || ::CFGetTypeID(mimeFileName) != ::CFStringGetTypeID()) {
michael@0 150 return nullptr;
michael@0 151 }
michael@0 152
michael@0 153 FSRef homeDir;
michael@0 154 if (::FSFindFolder(kUserDomain, kCurrentUserFolderType, kDontCreateFolder, &homeDir) != noErr) {
michael@0 155 return nullptr;
michael@0 156 }
michael@0 157
michael@0 158 CFURLRef userDirURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, &homeDir);
michael@0 159 if (!userDirURL) {
michael@0 160 return nullptr;
michael@0 161 }
michael@0 162
michael@0 163 AutoCFTypeObject userDirURLAutorelease(userDirURL);
michael@0 164 CFStringRef mimeFilePath = ::CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("Library/Preferences/%@"), static_cast<CFStringRef>(mimeFileName));
michael@0 165 if (!mimeFilePath) {
michael@0 166 return nullptr;
michael@0 167 }
michael@0 168
michael@0 169 AutoCFTypeObject mimeFilePathAutorelease(mimeFilePath);
michael@0 170 CFURLRef mimeFileURL = ::CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, mimeFilePath, kCFURLPOSIXPathStyle, false, userDirURL);
michael@0 171 if (!mimeFileURL) {
michael@0 172 return nullptr;
michael@0 173 }
michael@0 174
michael@0 175 AutoCFTypeObject mimeFileURLAutorelease(mimeFileURL);
michael@0 176 SInt32 errorCode = 0;
michael@0 177 CFDataRef mimeFileData = nullptr;
michael@0 178 Boolean result = ::CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, mimeFileURL, &mimeFileData, nullptr, nullptr, &errorCode);
michael@0 179 if (!result) {
michael@0 180 return nullptr;
michael@0 181 }
michael@0 182
michael@0 183 AutoCFTypeObject mimeFileDataAutorelease(mimeFileData);
michael@0 184 if (errorCode != 0) {
michael@0 185 return nullptr;
michael@0 186 }
michael@0 187
michael@0 188 CFPropertyListRef propertyList = ::CFPropertyListCreateFromXMLData(kCFAllocatorDefault, mimeFileData, kCFPropertyListImmutable, nullptr);
michael@0 189 if (!propertyList) {
michael@0 190 return nullptr;
michael@0 191 }
michael@0 192
michael@0 193 AutoCFTypeObject propertyListAutorelease(propertyList);
michael@0 194 if (::CFGetTypeID(propertyList) != ::CFDictionaryGetTypeID()) {
michael@0 195 return nullptr;
michael@0 196 }
michael@0 197
michael@0 198 CFTypeRef mimeTypes = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(propertyList), CFSTR("WebPluginMIMETypes"));
michael@0 199 if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0) {
michael@0 200 return nullptr;
michael@0 201 }
michael@0 202
michael@0 203 return static_cast<CFDictionaryRef>(::CFRetain(mimeTypes));
michael@0 204 }
michael@0 205
michael@0 206 static void ParsePlistPluginInfo(nsPluginInfo& info, CFBundleRef bundle)
michael@0 207 {
michael@0 208 CFDictionaryRef mimeDict = ParsePlistForMIMETypesFilename(bundle);
michael@0 209
michael@0 210 if (!mimeDict) {
michael@0 211 CFTypeRef mimeTypes = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypes"));
michael@0 212 if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0)
michael@0 213 return;
michael@0 214 mimeDict = static_cast<CFDictionaryRef>(::CFRetain(mimeTypes));
michael@0 215 }
michael@0 216
michael@0 217 AutoCFTypeObject mimeDictAutorelease(mimeDict);
michael@0 218 int mimeDictKeyCount = ::CFDictionaryGetCount(mimeDict);
michael@0 219
michael@0 220 // Allocate memory for mime data
michael@0 221 int mimeDataArraySize = mimeDictKeyCount * sizeof(char*);
michael@0 222 info.fMimeTypeArray = static_cast<char**>(NS_Alloc(mimeDataArraySize));
michael@0 223 if (!info.fMimeTypeArray)
michael@0 224 return;
michael@0 225 memset(info.fMimeTypeArray, 0, mimeDataArraySize);
michael@0 226 info.fExtensionArray = static_cast<char**>(NS_Alloc(mimeDataArraySize));
michael@0 227 if (!info.fExtensionArray)
michael@0 228 return;
michael@0 229 memset(info.fExtensionArray, 0, mimeDataArraySize);
michael@0 230 info.fMimeDescriptionArray = static_cast<char**>(NS_Alloc(mimeDataArraySize));
michael@0 231 if (!info.fMimeDescriptionArray)
michael@0 232 return;
michael@0 233 memset(info.fMimeDescriptionArray, 0, mimeDataArraySize);
michael@0 234
michael@0 235 // Allocate memory for mime dictionary keys and values
michael@0 236 nsAutoArrayPtr<CFTypeRef> keys(new CFTypeRef[mimeDictKeyCount]);
michael@0 237 if (!keys)
michael@0 238 return;
michael@0 239 nsAutoArrayPtr<CFTypeRef> values(new CFTypeRef[mimeDictKeyCount]);
michael@0 240 if (!values)
michael@0 241 return;
michael@0 242
michael@0 243 info.fVariantCount = 0;
michael@0 244
michael@0 245 ::CFDictionaryGetKeysAndValues(mimeDict, keys, values);
michael@0 246 for (int i = 0; i < mimeDictKeyCount; i++) {
michael@0 247 CFTypeRef mimeString = keys[i];
michael@0 248 if (!mimeString || ::CFGetTypeID(mimeString) != ::CFStringGetTypeID()) {
michael@0 249 continue;
michael@0 250 }
michael@0 251 CFTypeRef mimeDict = values[i];
michael@0 252 if (mimeDict && ::CFGetTypeID(mimeDict) == ::CFDictionaryGetTypeID()) {
michael@0 253 if (!MimeTypeEnabled(static_cast<CFDictionaryRef>(mimeDict))) {
michael@0 254 continue;
michael@0 255 }
michael@0 256 info.fMimeTypeArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(mimeString));
michael@0 257 if (!info.fMimeTypeArray[info.fVariantCount]) {
michael@0 258 continue;
michael@0 259 }
michael@0 260 CFTypeRef extensions = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginExtensions"));
michael@0 261 if (extensions && ::CFGetTypeID(extensions) == ::CFArrayGetTypeID()) {
michael@0 262 int extensionCount = ::CFArrayGetCount(static_cast<CFArrayRef>(extensions));
michael@0 263 CFMutableStringRef extensionList = ::CFStringCreateMutable(kCFAllocatorDefault, 0);
michael@0 264 for (int j = 0; j < extensionCount; j++) {
michael@0 265 CFTypeRef extension = ::CFArrayGetValueAtIndex(static_cast<CFArrayRef>(extensions), j);
michael@0 266 if (extension && ::CFGetTypeID(extension) == ::CFStringGetTypeID()) {
michael@0 267 if (j > 0)
michael@0 268 ::CFStringAppend(extensionList, CFSTR(","));
michael@0 269 ::CFStringAppend(static_cast<CFMutableStringRef>(extensionList), static_cast<CFStringRef>(extension));
michael@0 270 }
michael@0 271 }
michael@0 272 info.fExtensionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(extensionList));
michael@0 273 ::CFRelease(extensionList);
michael@0 274 }
michael@0 275 CFTypeRef description = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginTypeDescription"));
michael@0 276 if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID())
michael@0 277 info.fMimeDescriptionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description));
michael@0 278 }
michael@0 279 info.fVariantCount++;
michael@0 280 }
michael@0 281 }
michael@0 282
michael@0 283 nsPluginFile::nsPluginFile(nsIFile *spec)
michael@0 284 : mPlugin(spec)
michael@0 285 {
michael@0 286 }
michael@0 287
michael@0 288 nsPluginFile::~nsPluginFile() {}
michael@0 289
michael@0 290 nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
michael@0 291 {
michael@0 292 if (!mPlugin)
michael@0 293 return NS_ERROR_NULL_POINTER;
michael@0 294
michael@0 295 // 64-bit NSPR does not (yet) support bundles. So in 64-bit builds we need
michael@0 296 // (for now) to load the bundle's executable. However this can cause
michael@0 297 // problems: CFBundleCreate() doesn't run the bundle's executable's
michael@0 298 // initialization code, while NSAddImage() and dlopen() do run it. So using
michael@0 299 // NSPR's dyld loading mechanisms here (NSAddImage() or dlopen()) can cause
michael@0 300 // a bundle's initialization code to run earlier than expected, and lead to
michael@0 301 // crashes. See bug 577967.
michael@0 302 #ifdef __LP64__
michael@0 303 char executablePath[PATH_MAX];
michael@0 304 executablePath[0] = '\0';
michael@0 305 nsAutoCString bundlePath;
michael@0 306 mPlugin->GetNativePath(bundlePath);
michael@0 307 CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, bundlePath.get(),
michael@0 308 kCFStringEncodingUTF8);
michael@0 309 if (pathRef) {
michael@0 310 CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef,
michael@0 311 kCFURLPOSIXPathStyle,
michael@0 312 true);
michael@0 313 if (bundleURL) {
michael@0 314 CFBundleRef bundle = ::CFBundleCreate(nullptr, bundleURL);
michael@0 315 if (bundle) {
michael@0 316 CFURLRef executableURL = ::CFBundleCopyExecutableURL(bundle);
michael@0 317 if (executableURL) {
michael@0 318 if (!::CFURLGetFileSystemRepresentation(executableURL, true, (UInt8*)&executablePath, PATH_MAX))
michael@0 319 executablePath[0] = '\0';
michael@0 320 ::CFRelease(executableURL);
michael@0 321 }
michael@0 322 ::CFRelease(bundle);
michael@0 323 }
michael@0 324 ::CFRelease(bundleURL);
michael@0 325 }
michael@0 326 ::CFRelease(pathRef);
michael@0 327 }
michael@0 328 #else
michael@0 329 nsAutoCString bundlePath;
michael@0 330 mPlugin->GetNativePath(bundlePath);
michael@0 331 const char *executablePath = bundlePath.get();
michael@0 332 #endif
michael@0 333
michael@0 334 *outLibrary = PR_LoadLibrary(executablePath);
michael@0 335 pLibrary = *outLibrary;
michael@0 336 if (!pLibrary) {
michael@0 337 return NS_ERROR_FAILURE;
michael@0 338 }
michael@0 339 #ifdef DEBUG
michael@0 340 printf("[loaded plugin %s]\n", bundlePath.get());
michael@0 341 #endif
michael@0 342 return NS_OK;
michael@0 343 }
michael@0 344
michael@0 345 static char* p2cstrdup(StringPtr pstr)
michael@0 346 {
michael@0 347 int len = pstr[0];
michael@0 348 char* cstr = static_cast<char*>(NS_Alloc(len + 1));
michael@0 349 if (cstr) {
michael@0 350 memmove(cstr, pstr + 1, len);
michael@0 351 cstr[len] = '\0';
michael@0 352 }
michael@0 353 return cstr;
michael@0 354 }
michael@0 355
michael@0 356 static char* GetNextPluginStringFromHandle(Handle h, short *index)
michael@0 357 {
michael@0 358 char *ret = p2cstrdup((unsigned char*)(*h + *index));
michael@0 359 *index += (ret ? strlen(ret) : 0) + 1;
michael@0 360 return ret;
michael@0 361 }
michael@0 362
michael@0 363 static bool IsCompatibleArch(nsIFile *file)
michael@0 364 {
michael@0 365 CFURLRef pluginURL = nullptr;
michael@0 366 if (NS_FAILED(toCFURLRef(file, pluginURL)))
michael@0 367 return false;
michael@0 368
michael@0 369 bool isPluginFile = false;
michael@0 370
michael@0 371 CFBundleRef pluginBundle = ::CFBundleCreate(kCFAllocatorDefault, pluginURL);
michael@0 372 if (pluginBundle) {
michael@0 373 UInt32 packageType, packageCreator;
michael@0 374 ::CFBundleGetPackageInfo(pluginBundle, &packageType, &packageCreator);
michael@0 375 if (packageType == 'BRPL' || packageType == 'IEPL' || packageType == 'NSPL') {
michael@0 376 // Get path to plugin as a C string.
michael@0 377 char executablePath[PATH_MAX];
michael@0 378 executablePath[0] = '\0';
michael@0 379 if (!::CFURLGetFileSystemRepresentation(pluginURL, true, (UInt8*)&executablePath, PATH_MAX)) {
michael@0 380 executablePath[0] = '\0';
michael@0 381 }
michael@0 382
michael@0 383 uint32_t pluginLibArchitectures;
michael@0 384 nsresult rv = mozilla::ipc::GeckoChildProcessHost::GetArchitecturesForBinary(executablePath, &pluginLibArchitectures);
michael@0 385 if (NS_FAILED(rv)) {
michael@0 386 return false;
michael@0 387 }
michael@0 388
michael@0 389 uint32_t supportedArchitectures =
michael@0 390 #ifdef __LP64__
michael@0 391 mozilla::ipc::GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin);
michael@0 392 #else
michael@0 393 base::GetCurrentProcessArchitecture();
michael@0 394 #endif
michael@0 395
michael@0 396 // Consider the plugin architecture valid if there is any overlap in the masks.
michael@0 397 isPluginFile = !!(supportedArchitectures & pluginLibArchitectures);
michael@0 398 }
michael@0 399 ::CFRelease(pluginBundle);
michael@0 400 }
michael@0 401
michael@0 402 ::CFRelease(pluginURL);
michael@0 403 return isPluginFile;
michael@0 404 }
michael@0 405
michael@0 406 /**
michael@0 407 * Obtains all of the information currently available for this plugin.
michael@0 408 */
michael@0 409 nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
michael@0 410 {
michael@0 411 *outLibrary = nullptr;
michael@0 412
michael@0 413 nsresult rv = NS_OK;
michael@0 414
michael@0 415 if (!IsCompatibleArch(mPlugin)) {
michael@0 416 return NS_ERROR_FAILURE;
michael@0 417 }
michael@0 418
michael@0 419 // clear out the info, except for the first field.
michael@0 420 memset(&info, 0, sizeof(info));
michael@0 421
michael@0 422 // Try to get a bundle reference.
michael@0 423 nsAutoCString path;
michael@0 424 if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
michael@0 425 return rv;
michael@0 426 CFBundleRef bundle = getPluginBundle(path.get());
michael@0 427
michael@0 428 // fill in full path
michael@0 429 info.fFullPath = PL_strdup(path.get());
michael@0 430
michael@0 431 // fill in file name
michael@0 432 nsAutoCString fileName;
michael@0 433 if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
michael@0 434 return rv;
michael@0 435 info.fFileName = PL_strdup(fileName.get());
michael@0 436
michael@0 437 // Get fName
michael@0 438 if (bundle) {
michael@0 439 CFTypeRef name = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginName"));
michael@0 440 if (name && ::CFGetTypeID(name) == ::CFStringGetTypeID())
michael@0 441 info.fName = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(name));
michael@0 442 }
michael@0 443
michael@0 444 // Get fDescription
michael@0 445 if (bundle) {
michael@0 446 CFTypeRef description = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginDescription"));
michael@0 447 if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID())
michael@0 448 info.fDescription = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description));
michael@0 449 }
michael@0 450
michael@0 451 // Get fVersion
michael@0 452 if (bundle) {
michael@0 453 // Look for the release version first
michael@0 454 CFTypeRef version = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString"));
michael@0 455 if (!version) // try the build version
michael@0 456 version = ::CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey);
michael@0 457 if (version && ::CFGetTypeID(version) == ::CFStringGetTypeID())
michael@0 458 info.fVersion = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(version));
michael@0 459 }
michael@0 460
michael@0 461 // The last thing we need to do is get MIME data
michael@0 462 // fVariantCount, fMimeTypeArray, fExtensionArray, fMimeDescriptionArray
michael@0 463
michael@0 464 // First look for data in a bundle plist
michael@0 465 if (bundle) {
michael@0 466 ParsePlistPluginInfo(info, bundle);
michael@0 467 ::CFRelease(bundle);
michael@0 468 if (info.fVariantCount > 0)
michael@0 469 return NS_OK;
michael@0 470 }
michael@0 471
michael@0 472 // It's possible that our plugin has 2 entry points that'll give us mime type
michael@0 473 // info. Quicktime does this to get around the need of having admin rights to
michael@0 474 // change mime info in the resource fork. We need to use this info instead of
michael@0 475 // the resource. See bug 113464.
michael@0 476
michael@0 477 // Sadly we have to load the library for this to work.
michael@0 478 rv = LoadPlugin(outLibrary);
michael@0 479 if (NS_FAILED(rv))
michael@0 480 return rv;
michael@0 481
michael@0 482 // Try to get data from NP_GetMIMEDescription
michael@0 483 if (pLibrary) {
michael@0 484 NP_GETMIMEDESCRIPTION pfnGetMimeDesc = (NP_GETMIMEDESCRIPTION)PR_FindFunctionSymbol(pLibrary, NP_GETMIMEDESCRIPTION_NAME);
michael@0 485 if (pfnGetMimeDesc)
michael@0 486 ParsePluginMimeDescription(pfnGetMimeDesc(), info);
michael@0 487 if (info.fVariantCount)
michael@0 488 return NS_OK;
michael@0 489 }
michael@0 490
michael@0 491 // We'll fill this in using BP_GetSupportedMIMETypes and/or resource fork data
michael@0 492 BPSupportedMIMETypes mi = {kBPSupportedMIMETypesStructVers_1, nullptr, nullptr};
michael@0 493
michael@0 494 // Try to get data from BP_GetSupportedMIMETypes
michael@0 495 if (pLibrary) {
michael@0 496 BP_GETSUPPORTEDMIMETYPES pfnMime = (BP_GETSUPPORTEDMIMETYPES)PR_FindFunctionSymbol(pLibrary, "BP_GetSupportedMIMETypes");
michael@0 497 if (pfnMime && noErr == pfnMime(&mi, 0) && mi.typeStrings) {
michael@0 498 info.fVariantCount = (**(short**)mi.typeStrings) / 2;
michael@0 499 ::HLock(mi.typeStrings);
michael@0 500 if (mi.infoStrings) // it's possible some plugins have infoStrings missing
michael@0 501 ::HLock(mi.infoStrings);
michael@0 502 }
michael@0 503 }
michael@0 504
michael@0 505 // Fill in the info struct based on the data in the BPSupportedMIMETypes struct
michael@0 506 int variantCount = info.fVariantCount;
michael@0 507 info.fMimeTypeArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*)));
michael@0 508 if (!info.fMimeTypeArray)
michael@0 509 return NS_ERROR_OUT_OF_MEMORY;
michael@0 510 info.fExtensionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*)));
michael@0 511 if (!info.fExtensionArray)
michael@0 512 return NS_ERROR_OUT_OF_MEMORY;
michael@0 513 if (mi.infoStrings) {
michael@0 514 info.fMimeDescriptionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*)));
michael@0 515 if (!info.fMimeDescriptionArray)
michael@0 516 return NS_ERROR_OUT_OF_MEMORY;
michael@0 517 }
michael@0 518 short mimeIndex = 2;
michael@0 519 short descriptionIndex = 2;
michael@0 520 for (int i = 0; i < variantCount; i++) {
michael@0 521 info.fMimeTypeArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex);
michael@0 522 info.fExtensionArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex);
michael@0 523 if (mi.infoStrings)
michael@0 524 info.fMimeDescriptionArray[i] = GetNextPluginStringFromHandle(mi.infoStrings, &descriptionIndex);
michael@0 525 }
michael@0 526
michael@0 527 ::HUnlock(mi.typeStrings);
michael@0 528 ::DisposeHandle(mi.typeStrings);
michael@0 529 if (mi.infoStrings) {
michael@0 530 ::HUnlock(mi.infoStrings);
michael@0 531 ::DisposeHandle(mi.infoStrings);
michael@0 532 }
michael@0 533
michael@0 534 return NS_OK;
michael@0 535 }
michael@0 536
michael@0 537 nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info)
michael@0 538 {
michael@0 539 NS_Free(info.fName);
michael@0 540 NS_Free(info.fDescription);
michael@0 541 int variantCount = info.fVariantCount;
michael@0 542 for (int i = 0; i < variantCount; i++) {
michael@0 543 NS_Free(info.fMimeTypeArray[i]);
michael@0 544 NS_Free(info.fExtensionArray[i]);
michael@0 545 NS_Free(info.fMimeDescriptionArray[i]);
michael@0 546 }
michael@0 547 NS_Free(info.fMimeTypeArray);
michael@0 548 NS_Free(info.fMimeDescriptionArray);
michael@0 549 NS_Free(info.fExtensionArray);
michael@0 550 NS_Free(info.fFileName);
michael@0 551 NS_Free(info.fFullPath);
michael@0 552 NS_Free(info.fVersion);
michael@0 553
michael@0 554 return NS_OK;
michael@0 555 }

mercurial