1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/uriloader/exthandler/mac/nsOSHelperAppService.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,566 @@ 1.4 +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <sys/types.h> 1.11 +#include <sys/stat.h> 1.12 +#include "nsOSHelperAppService.h" 1.13 +#include "nsObjCExceptions.h" 1.14 +#include "nsISupports.h" 1.15 +#include "nsString.h" 1.16 +#include "nsTArray.h" 1.17 +#include "nsXPIDLString.h" 1.18 +#include "nsIURL.h" 1.19 +#include "nsIFile.h" 1.20 +#include "nsILocalFileMac.h" 1.21 +#include "nsMimeTypes.h" 1.22 +#include "nsIStringBundle.h" 1.23 +#include "nsIPromptService.h" 1.24 +#include "nsMemory.h" 1.25 +#include "nsCRT.h" 1.26 +#include "nsMIMEInfoMac.h" 1.27 +#include "nsEmbedCID.h" 1.28 + 1.29 +#import <CoreFoundation/CoreFoundation.h> 1.30 +#import <ApplicationServices/ApplicationServices.h> 1.31 + 1.32 +// chrome URL's 1.33 +#define HELPERAPPLAUNCHER_BUNDLE_URL "chrome://global/locale/helperAppLauncher.properties" 1.34 +#define BRAND_BUNDLE_URL "chrome://branding/locale/brand.properties" 1.35 + 1.36 +/* This is an undocumented interface (in the Foundation framework) that has 1.37 + * been stable since at least 10.2.8 and is still present on SnowLeopard. 1.38 + * Furthermore WebKit has three public methods (in WebKitSystemInterface.h) 1.39 + * that are thin wrappers around this interface's last three methods. So 1.40 + * it's unlikely to change anytime soon. Now that we're no longer using 1.41 + * Internet Config Services, this is the only way to look up a MIME type 1.42 + * from an extension, or vice versa. 1.43 + */ 1.44 +@class NSURLFileTypeMappingsInternal; 1.45 + 1.46 +@interface NSURLFileTypeMappings : NSObject 1.47 +{ 1.48 + NSURLFileTypeMappingsInternal *_internal; 1.49 +} 1.50 + 1.51 ++ (NSURLFileTypeMappings*)sharedMappings; 1.52 +- (NSString*)MIMETypeForExtension:(NSString*)aString; 1.53 +- (NSString*)preferredExtensionForMIMEType:(NSString*)aString; 1.54 +- (NSArray*)extensionsForMIMEType:(NSString*)aString; 1.55 +@end 1.56 + 1.57 +nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() 1.58 +{ 1.59 + mode_t mask = umask(0777); 1.60 + umask(mask); 1.61 + mPermissions = 0666 & ~mask; 1.62 +} 1.63 + 1.64 +nsOSHelperAppService::~nsOSHelperAppService() 1.65 +{} 1.66 + 1.67 +nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, bool * aHandlerExists) 1.68 +{ 1.69 + // CFStringCreateWithBytes() can fail even if we're not out of memory -- 1.70 + // for example if the 'bytes' parameter is something very wierd (like "ÿÿ~" 1.71 + // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's 1.72 + // specified in the 'encoding' parameter. See bug 548719. 1.73 + CFStringRef schemeString = ::CFStringCreateWithBytes(kCFAllocatorDefault, 1.74 + (const UInt8*)aProtocolScheme, 1.75 + strlen(aProtocolScheme), 1.76 + kCFStringEncodingUTF8, 1.77 + false); 1.78 + if (schemeString) { 1.79 + // LSCopyDefaultHandlerForURLScheme() can fail to find the default handler 1.80 + // for aProtocolScheme when it's never been explicitly set (using 1.81 + // LSSetDefaultHandlerForURLScheme()). For example, Safari is the default 1.82 + // handler for the "http" scheme on a newly installed copy of OS X. But 1.83 + // this (presumably) wasn't done using LSSetDefaultHandlerForURLScheme(), 1.84 + // so LSCopyDefaultHandlerForURLScheme() will fail to find Safari. To get 1.85 + // around this we use LSCopyAllHandlersForURLScheme() instead -- which seems 1.86 + // never to fail. 1.87 + // http://lists.apple.com/archives/Carbon-dev/2007/May/msg00349.html 1.88 + // http://www.realsoftware.com/listarchives/realbasic-nug/2008-02/msg00119.html 1.89 + CFArrayRef handlerArray = ::LSCopyAllHandlersForURLScheme(schemeString); 1.90 + *aHandlerExists = !!handlerArray; 1.91 + if (handlerArray) 1.92 + ::CFRelease(handlerArray); 1.93 + ::CFRelease(schemeString); 1.94 + } else { 1.95 + *aHandlerExists = false; 1.96 + } 1.97 + return NS_OK; 1.98 +} 1.99 + 1.100 +NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval) 1.101 +{ 1.102 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.103 + 1.104 + nsresult rv = NS_ERROR_NOT_AVAILABLE; 1.105 + 1.106 + CFStringRef schemeCFString = 1.107 + ::CFStringCreateWithBytes(kCFAllocatorDefault, 1.108 + (const UInt8 *)PromiseFlatCString(aScheme).get(), 1.109 + aScheme.Length(), 1.110 + kCFStringEncodingUTF8, 1.111 + false); 1.112 + 1.113 + if (schemeCFString) { 1.114 + CFStringRef lookupCFString = ::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString); 1.115 + 1.116 + if (lookupCFString) { 1.117 + CFURLRef lookupCFURL = ::CFURLCreateWithString(NULL, lookupCFString, NULL); 1.118 + 1.119 + if (lookupCFURL) { 1.120 + CFURLRef appCFURL = NULL; 1.121 + OSStatus theErr = ::LSGetApplicationForURL(lookupCFURL, kLSRolesAll, NULL, &appCFURL); 1.122 + 1.123 + if (theErr == noErr) { 1.124 + CFBundleRef handlerBundle = ::CFBundleCreate(NULL, appCFURL); 1.125 + 1.126 + if (handlerBundle) { 1.127 + // Get the human-readable name of the default handler bundle 1.128 + CFStringRef bundleName = 1.129 + (CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle, 1.130 + kCFBundleNameKey); 1.131 + 1.132 + if (bundleName) { 1.133 + nsAutoTArray<UniChar, 255> buffer; 1.134 + CFIndex bundleNameLength = ::CFStringGetLength(bundleName); 1.135 + buffer.SetLength(bundleNameLength); 1.136 + ::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength), 1.137 + buffer.Elements()); 1.138 + _retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), bundleNameLength); 1.139 + rv = NS_OK; 1.140 + } 1.141 + 1.142 + ::CFRelease(handlerBundle); 1.143 + } 1.144 + 1.145 + ::CFRelease(appCFURL); 1.146 + } 1.147 + 1.148 + ::CFRelease(lookupCFURL); 1.149 + } 1.150 + 1.151 + ::CFRelease(lookupCFString); 1.152 + } 1.153 + 1.154 + ::CFRelease(schemeCFString); 1.155 + } 1.156 + 1.157 + return rv; 1.158 + 1.159 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.160 +} 1.161 + 1.162 +nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t * aPlatformAppPath, nsIFile ** aFile) 1.163 +{ 1.164 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.165 + 1.166 + nsresult rv; 1.167 + nsCOMPtr<nsILocalFileMac> localFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); 1.168 + NS_ENSURE_SUCCESS(rv,rv); 1.169 + 1.170 + CFURLRef pathAsCFURL; 1.171 + CFStringRef pathAsCFString = ::CFStringCreateWithCharacters(NULL, 1.172 + reinterpret_cast<const UniChar*>(aPlatformAppPath), 1.173 + NS_strlen(aPlatformAppPath)); 1.174 + if (!pathAsCFString) 1.175 + return NS_ERROR_OUT_OF_MEMORY; 1.176 + 1.177 + if (::CFStringGetCharacterAtIndex(pathAsCFString, 0) == '/') { 1.178 + // we have a Posix path 1.179 + pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, 1.180 + kCFURLPOSIXPathStyle, false); 1.181 + if (!pathAsCFURL) { 1.182 + ::CFRelease(pathAsCFString); 1.183 + return NS_ERROR_OUT_OF_MEMORY; 1.184 + } 1.185 + } 1.186 + else { 1.187 + // if it doesn't start with a / it's not an absolute Posix path 1.188 + // let's check if it's a HFS path left over from old preferences 1.189 + 1.190 + // If it starts with a ':' char, it's not an absolute HFS path 1.191 + // so bail for that, and also if it's empty 1.192 + if (::CFStringGetLength(pathAsCFString) == 0 || 1.193 + ::CFStringGetCharacterAtIndex(pathAsCFString, 0) == ':') 1.194 + { 1.195 + ::CFRelease(pathAsCFString); 1.196 + return NS_ERROR_FILE_UNRECOGNIZED_PATH; 1.197 + } 1.198 + 1.199 + pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, 1.200 + kCFURLHFSPathStyle, false); 1.201 + if (!pathAsCFURL) { 1.202 + ::CFRelease(pathAsCFString); 1.203 + return NS_ERROR_OUT_OF_MEMORY; 1.204 + } 1.205 + } 1.206 + 1.207 + rv = localFile->InitWithCFURL(pathAsCFURL); 1.208 + ::CFRelease(pathAsCFString); 1.209 + ::CFRelease(pathAsCFURL); 1.210 + if (NS_FAILED(rv)) 1.211 + return rv; 1.212 + *aFile = localFile; 1.213 + NS_IF_ADDREF(*aFile); 1.214 + 1.215 + return NS_OK; 1.216 + 1.217 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.218 +} 1.219 + 1.220 +NS_IMETHODIMP nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsIMIMEInfo ** aMIMEInfo) 1.221 +{ 1.222 + return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo); 1.223 +} 1.224 + 1.225 +// Returns the MIME types an application bundle explicitly claims to handle. 1.226 +// Returns NULL if aAppRef doesn't explicitly claim to handle any MIME types. 1.227 +// If the return value is non-NULL, the caller is responsible for freeing it. 1.228 +// This isn't necessarily the same as the MIME types the application bundle 1.229 +// is registered to handle in the Launch Services database. (For example 1.230 +// the Preview application is normally registered to handle the application/pdf 1.231 +// MIME type, even though it doesn't explicitly claim to handle *any* MIME 1.232 +// types in its Info.plist. This is probably because Preview does explicitly 1.233 +// claim to handle the com.adobe.pdf UTI, and Launch Services somehow 1.234 +// translates this into a claim to support the application/pdf MIME type. 1.235 +// Launch Services doesn't provide any APIs (documented or undocumented) to 1.236 +// query which MIME types a given application is registered to handle. So any 1.237 +// app that wants this information (e.g. the Default Apps pref pane) needs to 1.238 +// iterate through the entire Launch Services database -- a process which can 1.239 +// take several seconds.) 1.240 +static CFArrayRef GetMIMETypesHandledByApp(FSRef *aAppRef) 1.241 +{ 1.242 + CFURLRef appURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aAppRef); 1.243 + if (!appURL) { 1.244 + return NULL; 1.245 + } 1.246 + CFDictionaryRef infoDict = ::CFBundleCopyInfoDictionaryForURL(appURL); 1.247 + ::CFRelease(appURL); 1.248 + if (!infoDict) { 1.249 + return NULL; 1.250 + } 1.251 + CFTypeRef cfObject = ::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes")); 1.252 + if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) { 1.253 + ::CFRelease(infoDict); 1.254 + return NULL; 1.255 + } 1.256 + 1.257 + CFArrayRef docTypes = static_cast<CFArrayRef>(cfObject); 1.258 + CFIndex docTypesCount = ::CFArrayGetCount(docTypes); 1.259 + if (docTypesCount == 0) { 1.260 + ::CFRelease(infoDict); 1.261 + return NULL; 1.262 + } 1.263 + 1.264 + CFMutableArrayRef mimeTypes = 1.265 + ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 1.266 + for (CFIndex i = 0; i < docTypesCount; ++i) { 1.267 + cfObject = ::CFArrayGetValueAtIndex(docTypes, i); 1.268 + if (!cfObject || (::CFGetTypeID(cfObject) != ::CFDictionaryGetTypeID())) { 1.269 + continue; 1.270 + } 1.271 + CFDictionaryRef typeDict = static_cast<CFDictionaryRef>(cfObject); 1.272 + 1.273 + // When this key is present (on OS X 10.5 and later), its contents 1.274 + // take precedence over CFBundleTypeMIMETypes (and CFBundleTypeExtensions 1.275 + // and CFBundleTypeOSTypes). 1.276 + cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("LSItemContentTypes")); 1.277 + if (cfObject && (::CFGetTypeID(cfObject) == ::CFArrayGetTypeID())) { 1.278 + continue; 1.279 + } 1.280 + 1.281 + cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("CFBundleTypeMIMETypes")); 1.282 + if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) { 1.283 + continue; 1.284 + } 1.285 + CFArrayRef mimeTypeHolder = static_cast<CFArrayRef>(cfObject); 1.286 + CFArrayAppendArray(mimeTypes, mimeTypeHolder, 1.287 + ::CFRangeMake(0, ::CFArrayGetCount(mimeTypeHolder))); 1.288 + } 1.289 + 1.290 + ::CFRelease(infoDict); 1.291 + if (!::CFArrayGetCount(mimeTypes)) { 1.292 + ::CFRelease(mimeTypes); 1.293 + mimeTypes = NULL; 1.294 + } 1.295 + return mimeTypes; 1.296 +} 1.297 + 1.298 +// aMIMEType and aFileExt might not match, If they don't we set *aFound to 1.299 +// false and return a minimal nsIMIMEInfo structure. 1.300 +already_AddRefed<nsIMIMEInfo> 1.301 +nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, 1.302 + const nsACString& aFileExt, 1.303 + bool * aFound) 1.304 +{ 1.305 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL; 1.306 + 1.307 + *aFound = false; 1.308 + 1.309 + const nsCString& flatType = PromiseFlatCString(aMIMEType); 1.310 + const nsCString& flatExt = PromiseFlatCString(aFileExt); 1.311 + 1.312 + PR_LOG(mLog, PR_LOG_DEBUG, ("Mac: HelperAppService lookup for type '%s' ext '%s'\n", 1.313 + flatType.get(), flatExt.get())); 1.314 + 1.315 + // Create a Mac-specific MIME info so we can use Mac-specific members. 1.316 + nsRefPtr<nsMIMEInfoMac> mimeInfoMac = new nsMIMEInfoMac(aMIMEType); 1.317 + 1.318 + NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; 1.319 + 1.320 + OSStatus err; 1.321 + bool haveAppForType = false; 1.322 + bool haveAppForExt = false; 1.323 + bool typeAppIsDefault = false; 1.324 + bool extAppIsDefault = false; 1.325 + FSRef typeAppFSRef; 1.326 + FSRef extAppFSRef; 1.327 + 1.328 + CFStringRef cfMIMEType = NULL; 1.329 + 1.330 + if (!aMIMEType.IsEmpty()) { 1.331 + CFURLRef appURL = NULL; 1.332 + // CFStringCreateWithCString() can fail even if we're not out of memory -- 1.333 + // for example if the 'cStr' parameter is something very wierd (like "ÿÿ~" 1.334 + // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's 1.335 + // specified in the 'encoding' parameter. See bug 548719. 1.336 + cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(), 1.337 + kCFStringEncodingUTF8); 1.338 + if (cfMIMEType) { 1.339 + err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL); 1.340 + if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) { 1.341 + haveAppForType = true; 1.342 + PR_LOG(mLog, PR_LOG_DEBUG, ("LSCopyApplicationForMIMEType found a default application\n")); 1.343 + } 1.344 + if (appURL) { 1.345 + ::CFRelease(appURL); 1.346 + } 1.347 + } 1.348 + } 1.349 + if (!aFileExt.IsEmpty()) { 1.350 + // CFStringCreateWithCString() can fail even if we're not out of memory -- 1.351 + // for example if the 'cStr' parameter is something very wierd (like "ÿÿ~" 1.352 + // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's 1.353 + // specified in the 'encoding' parameter. See bug 548719. 1.354 + CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8); 1.355 + if (cfExt) { 1.356 + err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt, 1.357 + kLSRolesAll, &extAppFSRef, nullptr); 1.358 + if (err == noErr) { 1.359 + haveAppForExt = true; 1.360 + PR_LOG(mLog, PR_LOG_DEBUG, ("LSGetApplicationForInfo found a default application\n")); 1.361 + } 1.362 + ::CFRelease(cfExt); 1.363 + } 1.364 + } 1.365 + 1.366 + if (haveAppForType && haveAppForExt) { 1.367 + // Do aMIMEType and aFileExt match? 1.368 + if (::FSCompareFSRefs((const FSRef *) &typeAppFSRef, (const FSRef *) &extAppFSRef) == noErr) { 1.369 + typeAppIsDefault = true; 1.370 + *aFound = true; 1.371 + } 1.372 + } else if (haveAppForType) { 1.373 + // If aFileExt isn't empty, it doesn't match aMIMEType. 1.374 + if (aFileExt.IsEmpty()) { 1.375 + typeAppIsDefault = true; 1.376 + *aFound = true; 1.377 + } 1.378 + } else if (haveAppForExt) { 1.379 + // If aMIMEType isn't empty, it doesn't match aFileExt, which should mean 1.380 + // that we haven't found a matching app. But make an exception for an app 1.381 + // that also explicitly claims to handle aMIMEType, or which doesn't claim 1.382 + // to handle any MIME types. This helps work around the following Apple 1.383 + // design flaw: 1.384 + // 1.385 + // Launch Services is somewhat unreliable about registering Apple apps to 1.386 + // handle MIME types. Probably this is because Apple has officially 1.387 + // deprecated support for MIME types (in favor of UTIs). As a result, 1.388 + // most of Apple's own apps don't explicitly claim to handle any MIME 1.389 + // types (instead they claim to handle one or more UTIs). So Launch 1.390 + // Services must contain logic to translate support for a given UTI into 1.391 + // support for one or more MIME types, and it doesn't always do this 1.392 + // correctly. For example DiskImageMounter isn't (by default) registered 1.393 + // to handle the application/x-apple-diskimage MIME type. See bug 675356. 1.394 + // 1.395 + // Apple has also deprecated support for file extensions, and Apple apps 1.396 + // also don't register to handle them. But for some reason Launch Services 1.397 + // is (apparently) better about translating support for a given UTI into 1.398 + // support for one or more file extensions. It's not at all clear why. 1.399 + if (aMIMEType.IsEmpty()) { 1.400 + extAppIsDefault = true; 1.401 + *aFound = true; 1.402 + } else { 1.403 + CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef); 1.404 + if (extAppMIMETypes) { 1.405 + if (cfMIMEType) { 1.406 + if (::CFArrayContainsValue(extAppMIMETypes, 1.407 + ::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)), 1.408 + cfMIMEType)) { 1.409 + extAppIsDefault = true; 1.410 + *aFound = true; 1.411 + } 1.412 + } 1.413 + ::CFRelease(extAppMIMETypes); 1.414 + } else { 1.415 + extAppIsDefault = true; 1.416 + *aFound = true; 1.417 + } 1.418 + } 1.419 + } 1.420 + 1.421 + if (cfMIMEType) { 1.422 + ::CFRelease(cfMIMEType); 1.423 + } 1.424 + 1.425 + if (aMIMEType.IsEmpty()) { 1.426 + if (haveAppForExt) { 1.427 + // If aMIMEType is empty and we've found a default app for aFileExt, try 1.428 + // to get the MIME type from aFileExt. (It might also be worth doing 1.429 + // this when aMIMEType isn't empty but haveAppForType is false -- but 1.430 + // the doc for this method says that if we have a MIME type (in 1.431 + // aMIMEType), we need to give it preference.) 1.432 + NSURLFileTypeMappings *map = [NSURLFileTypeMappings sharedMappings]; 1.433 + NSString *extStr = [NSString stringWithCString:flatExt.get() encoding:NSASCIIStringEncoding]; 1.434 + NSString *typeStr = map ? [map MIMETypeForExtension:extStr] : NULL; 1.435 + if (typeStr) { 1.436 + nsAutoCString mimeType; 1.437 + mimeType.Assign((char *)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]); 1.438 + mimeInfoMac->SetMIMEType(mimeType); 1.439 + haveAppForType = true; 1.440 + } else { 1.441 + // Sometimes the OS won't give us a MIME type for an extension that's 1.442 + // registered with Launch Services and has a default app: For example 1.443 + // Real Player registers itself for the "ogg" extension and for the 1.444 + // audio/x-ogg and application/x-ogg MIME types, but 1.445 + // MIMETypeForExtension returns nil for the "ogg" extension even on 1.446 + // systems where Real Player is installed. This is probably an Apple 1.447 + // bug. But bad things happen if we return an nsIMIMEInfo structure 1.448 + // with an empty MIME type and set *aFound to true. So in this 1.449 + // case we need to set it to false here. 1.450 + haveAppForExt = false; 1.451 + extAppIsDefault = false; 1.452 + *aFound = false; 1.453 + } 1.454 + } else { 1.455 + // Otherwise set the MIME type to a reasonable fallback. 1.456 + mimeInfoMac->SetMIMEType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM)); 1.457 + } 1.458 + } 1.459 + 1.460 + if (typeAppIsDefault || extAppIsDefault) { 1.461 + if (haveAppForExt) 1.462 + mimeInfoMac->AppendExtension(aFileExt); 1.463 + 1.464 + nsCOMPtr<nsILocalFileMac> app(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); 1.465 + if (!app) { 1.466 + [localPool release]; 1.467 + return nullptr; 1.468 + } 1.469 + 1.470 + CFStringRef cfAppName = NULL; 1.471 + if (typeAppIsDefault) { 1.472 + app->InitWithFSRef(&typeAppFSRef); 1.473 + ::LSCopyItemAttribute((const FSRef *) &typeAppFSRef, kLSRolesAll, 1.474 + kLSItemDisplayName, (CFTypeRef *) &cfAppName); 1.475 + } else { 1.476 + app->InitWithFSRef(&extAppFSRef); 1.477 + ::LSCopyItemAttribute((const FSRef *) &extAppFSRef, kLSRolesAll, 1.478 + kLSItemDisplayName, (CFTypeRef *) &cfAppName); 1.479 + } 1.480 + if (cfAppName) { 1.481 + nsAutoTArray<UniChar, 255> buffer; 1.482 + CFIndex appNameLength = ::CFStringGetLength(cfAppName); 1.483 + buffer.SetLength(appNameLength); 1.484 + ::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength), 1.485 + buffer.Elements()); 1.486 + nsAutoString appName; 1.487 + appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), appNameLength); 1.488 + mimeInfoMac->SetDefaultDescription(appName); 1.489 + ::CFRelease(cfAppName); 1.490 + } 1.491 + 1.492 + mimeInfoMac->SetDefaultApplication(app); 1.493 + mimeInfoMac->SetPreferredAction(nsIMIMEInfo::useSystemDefault); 1.494 + } else { 1.495 + mimeInfoMac->SetPreferredAction(nsIMIMEInfo::saveToDisk); 1.496 + } 1.497 + 1.498 + nsAutoCString mimeType; 1.499 + mimeInfoMac->GetMIMEType(mimeType); 1.500 + if (*aFound && !mimeType.IsEmpty()) { 1.501 + // If we have a MIME type, make sure its preferred extension is included 1.502 + // in our list. 1.503 + NSURLFileTypeMappings *map = [NSURLFileTypeMappings sharedMappings]; 1.504 + NSString *typeStr = [NSString stringWithCString:mimeType.get() encoding:NSASCIIStringEncoding]; 1.505 + NSString *extStr = map ? [map preferredExtensionForMIMEType:typeStr] : NULL; 1.506 + if (extStr) { 1.507 + nsAutoCString preferredExt; 1.508 + preferredExt.Assign((char *)[extStr cStringUsingEncoding:NSASCIIStringEncoding]); 1.509 + mimeInfoMac->AppendExtension(preferredExt); 1.510 + } 1.511 + 1.512 + CFStringRef cfType = ::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8); 1.513 + if (cfType) { 1.514 + CFStringRef cfTypeDesc = NULL; 1.515 + if (::LSCopyKindStringForMIMEType(cfType, &cfTypeDesc) == noErr) { 1.516 + nsAutoTArray<UniChar, 255> buffer; 1.517 + CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc); 1.518 + buffer.SetLength(typeDescLength); 1.519 + ::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength), 1.520 + buffer.Elements()); 1.521 + nsAutoString typeDesc; 1.522 + typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), typeDescLength); 1.523 + mimeInfoMac->SetDescription(typeDesc); 1.524 + } 1.525 + if (cfTypeDesc) { 1.526 + ::CFRelease(cfTypeDesc); 1.527 + } 1.528 + ::CFRelease(cfType); 1.529 + } 1.530 + } 1.531 + 1.532 + PR_LOG(mLog, PR_LOG_DEBUG, ("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound)); 1.533 + 1.534 + [localPool release]; 1.535 + return mimeInfoMac.forget(); 1.536 + 1.537 + NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL; 1.538 +} 1.539 + 1.540 +NS_IMETHODIMP 1.541 +nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString &aScheme, 1.542 + bool *found, 1.543 + nsIHandlerInfo **_retval) 1.544 +{ 1.545 + NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!"); 1.546 + 1.547 + nsresult rv = OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(), 1.548 + found); 1.549 + if (NS_FAILED(rv)) 1.550 + return rv; 1.551 + 1.552 + nsMIMEInfoMac *handlerInfo = 1.553 + new nsMIMEInfoMac(aScheme, nsMIMEInfoBase::eProtocolInfo); 1.554 + NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY); 1.555 + NS_ADDREF(*_retval = handlerInfo); 1.556 + 1.557 + if (!*found) { 1.558 + // Code that calls this requires an object regardless if the OS has 1.559 + // something for us, so we return the empty object. 1.560 + return NS_OK; 1.561 + } 1.562 + 1.563 + nsAutoString desc; 1.564 + GetApplicationDescription(aScheme, desc); 1.565 + handlerInfo->SetDefaultDescription(desc); 1.566 + 1.567 + return NS_OK; 1.568 +} 1.569 +