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 +}