diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/Plugins/WebBasePluginPackage.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKit/Plugins/WebBasePluginPackage.m Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +#import +#import +#import +#import +#import +#import + +#import + +#import "WebKitLogging.h" +#import "WebTypesInternal.h" + +#import +#import + +#define JavaCocoaPluginIdentifier @"com.apple.JavaPluginCocoa" +#define JavaCarbonPluginIdentifier @"com.apple.JavaAppletPlugin" +#define JavaCFMPluginFilename @"Java Applet Plugin Enabler" + +#define QuickTimeCarbonPluginIdentifier @"com.apple.QuickTime Plugin.plugin" +#define QuickTimeCocoaPluginIdentifier @"com.apple.quicktime.webplugin" + +@interface NSArray (WebPluginExtensions) +- (NSArray *)_web_lowercaseStrings; +@end; + +@implementation WebBasePluginPackage + +#ifndef BUILDING_ON_TIGER ++ (void)initialize +{ + WebCoreObjCFinalizeOnMainThread(self); +} +#endif + ++ (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath +{ + + WebBasePluginPackage *pluginPackage = [[WebPluginPackage alloc] initWithPath:pluginPath]; + + if (!pluginPackage) { +#ifdef __LP64__ + return nil; +#else + pluginPackage = [[WebNetscapePluginPackage alloc] initWithPath:pluginPath]; +#endif + } + + return [pluginPackage autorelease]; +} + ++ (NSString *)preferredLocalizationName +{ + return WebCFAutorelease(WKCopyCFLocalizationPreferredName(NULL)); +} + +- (NSString *)pathByResolvingSymlinksAndAliasesInPath:(NSString *)thePath +{ + NSString *newPath = [thePath stringByResolvingSymlinksInPath]; + + FSRef fref; + OSStatus err; + + err = FSPathMakeRef((const UInt8 *)[thePath fileSystemRepresentation], &fref, NULL); + if (err != noErr) + return newPath; + + Boolean targetIsFolder; + Boolean wasAliased; + err = FSResolveAliasFileWithMountFlags(&fref, TRUE, &targetIsFolder, &wasAliased, kResolveAliasFileNoUI); + if (err != noErr) + return newPath; + + if (wasAliased) { + CFURLRef URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fref); + newPath = [(NSURL *)URL path]; + CFRelease(URL); + } + + return newPath; +} + +- (id)initWithPath:(NSString *)pluginPath +{ + if (!(self = [super init])) + return nil; + + path = [[self pathByResolvingSymlinksAndAliasesInPath:pluginPath] retain]; + bundle = [[NSBundle alloc] initWithPath:path]; +#ifndef __ppc__ + // 32-bit PowerPC is the only platform where non-bundled CFM plugins are supported + if (!bundle) { + [self release]; + return nil; + } +#endif + cfBundle = CFBundleCreate(NULL, (CFURLRef)[NSURL fileURLWithPath:path]); + extensionToMIME = [[NSMutableDictionary alloc] init]; + + return self; +} + +- (BOOL)getPluginInfoFromBundleAndMIMEDictionary:(NSDictionary *)MIMETypes +{ + if (!bundle) + return NO; + + if (!MIMETypes) { + MIMETypes = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesKey]; + if (!MIMETypes) + return NO; + } + + NSMutableDictionary *MIMEToExtensionsDictionary = [NSMutableDictionary dictionary]; + NSMutableDictionary *MIMEToDescriptionDictionary = [NSMutableDictionary dictionary]; + NSEnumerator *keyEnumerator = [MIMETypes keyEnumerator]; + NSDictionary *MIMEDictionary; + NSString *MIME, *description; + NSArray *extensions; + + while ((MIME = [keyEnumerator nextObject]) != nil) { + MIMEDictionary = [MIMETypes objectForKey:MIME]; + + // FIXME: Consider storing disabled MIME types. + NSNumber *isEnabled = [MIMEDictionary objectForKey:WebPluginTypeEnabledKey]; + if (isEnabled && [isEnabled boolValue] == NO) + continue; + + extensions = [[MIMEDictionary objectForKey:WebPluginExtensionsKey] _web_lowercaseStrings]; + if ([extensions count] == 0) + extensions = [NSArray arrayWithObject:@""]; + + MIME = [MIME lowercaseString]; + + [MIMEToExtensionsDictionary setObject:extensions forKey:MIME]; + + description = [MIMEDictionary objectForKey:WebPluginTypeDescriptionKey]; + if (!description) + description = @""; + + [MIMEToDescriptionDictionary setObject:description forKey:MIME]; + } + + [self setMIMEToExtensionsDictionary:MIMEToExtensionsDictionary]; + [self setMIMEToDescriptionDictionary:MIMEToDescriptionDictionary]; + + NSString *filename = [self filename]; + + NSString *theName = [bundle objectForInfoDictionaryKey:WebPluginNameKey]; + if (!theName) + theName = filename; + [self setName:theName]; + + description = [bundle objectForInfoDictionaryKey:WebPluginDescriptionKey]; + if (!description) + description = filename; + [self setPluginDescription:description]; + + return YES; +} + +- (NSDictionary *)pListForPath:(NSString *)pListPath createFile:(BOOL)createFile +{ + if (createFile && [self load] && BP_CreatePluginMIMETypesPreferences) + BP_CreatePluginMIMETypesPreferences(); + + NSDictionary *pList = nil; + NSData *data = [NSData dataWithContentsOfFile:pListPath]; + if (data) { + pList = [NSPropertyListSerialization propertyListFromData:data + mutabilityOption:NSPropertyListImmutable + format:nil + errorDescription:nil]; + } + + return pList; +} + +- (BOOL)getPluginInfoFromPLists +{ + if (!bundle) + return NO; + + NSDictionary *MIMETypes = nil; + NSString *pListFilename = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesFilenameKey]; + + // Check if the MIME types are claimed in a plist in the user's preferences directory. + if (pListFilename) { + NSString *pListPath = [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), pListFilename]; + NSDictionary *pList = [self pListForPath:pListPath createFile:NO]; + if (pList) { + // If the plist isn't localized, have the plug-in recreate it in the preferred language. + NSString *localizationName = [pList objectForKey:WebPluginLocalizationNameKey]; + if (![localizationName isEqualToString:[[self class] preferredLocalizationName]]) + pList = [self pListForPath:pListPath createFile:YES]; + MIMETypes = [pList objectForKey:WebPluginMIMETypesKey]; + } else + // Plist doesn't exist, ask the plug-in to create it. + MIMETypes = [[self pListForPath:pListPath createFile:YES] objectForKey:WebPluginMIMETypesKey]; + } + + // Pass the MIME dictionary to the superclass to parse it. + return [self getPluginInfoFromBundleAndMIMEDictionary:MIMETypes]; +} + +- (BOOL)load +{ + if (bundle && !BP_CreatePluginMIMETypesPreferences) + BP_CreatePluginMIMETypesPreferences = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("BP_CreatePluginMIMETypesPreferences")); + + return YES; +} + +- (void)dealloc +{ + ASSERT(!pluginDatabases || [pluginDatabases count] == 0); + [pluginDatabases release]; + + [name release]; + [path release]; + [pluginDescription release]; + + [MIMEToDescription release]; + [MIMEToExtensions release]; + [extensionToMIME release]; + + [bundle release]; + if (cfBundle) + CFRelease(cfBundle); + + [super dealloc]; +} + +- (void)finalize +{ + ASSERT_MAIN_THREAD(); + ASSERT(!pluginDatabases || [pluginDatabases count] == 0); + [pluginDatabases release]; + + if (cfBundle) + CFRelease(cfBundle); + + [super finalize]; +} + +- (NSString *)name +{ + return name; +} + +- (NSString *)path +{ + return path; +} + +- (NSString *)filename +{ + return [path lastPathComponent]; +} + +- (NSString *)pluginDescription +{ + return pluginDescription; +} + +- (NSEnumerator *)extensionEnumerator +{ + return [extensionToMIME keyEnumerator]; +} + +- (NSEnumerator *)MIMETypeEnumerator +{ + return [MIMEToExtensions keyEnumerator]; +} + +- (NSString *)descriptionForMIMEType:(NSString *)MIMEType +{ + return [MIMEToDescription objectForKey:MIMEType]; +} + +- (NSString *)MIMETypeForExtension:(NSString *)extension +{ + return [extensionToMIME objectForKey:extension]; +} + +- (NSArray *)extensionsForMIMEType:(NSString *)MIMEType +{ + return [MIMEToExtensions objectForKey:MIMEType]; +} + +- (NSBundle *)bundle +{ + return bundle; +} + +- (void)setName:(NSString *)theName +{ + [name release]; + name = [theName retain]; +} + +- (void)setPath:(NSString *)thePath +{ + [path release]; + path = [thePath retain]; +} + +- (void)setPluginDescription:(NSString *)description +{ + [pluginDescription release]; + pluginDescription = [description retain]; +} + +- (void)setMIMEToDescriptionDictionary:(NSDictionary *)MIMEToDescriptionDictionary +{ + [MIMEToDescription release]; + MIMEToDescription = [MIMEToDescriptionDictionary retain]; +} + +- (void)setMIMEToExtensionsDictionary:(NSDictionary *)MIMEToExtensionsDictionary +{ + [MIMEToExtensions release]; + MIMEToExtensions = [MIMEToExtensionsDictionary retain]; + + // Reverse the mapping + [extensionToMIME removeAllObjects]; + + NSEnumerator *MIMEEnumerator = [MIMEToExtensions keyEnumerator], *extensionEnumerator; + NSString *MIME, *extension; + NSArray *extensions; + + while ((MIME = [MIMEEnumerator nextObject]) != nil) { + extensions = [MIMEToExtensions objectForKey:MIME]; + extensionEnumerator = [extensions objectEnumerator]; + + while ((extension = [extensionEnumerator nextObject]) != nil) { + if (![extension isEqualToString:@""]) + [extensionToMIME setObject:MIME forKey:extension]; + } + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"name: %@\npath: %@\nmimeTypes:\n%@\npluginDescription:%@", + name, path, [MIMEToExtensions description], [MIMEToDescription description], pluginDescription]; +} + +- (BOOL)isQuickTimePlugIn +{ + NSString *bundleIdentifier = [[self bundle] bundleIdentifier]; + return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCarbonPluginIdentifier] || + [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCocoaPluginIdentifier]; +} + +- (BOOL)isJavaPlugIn +{ + NSString *bundleIdentifier = [[self bundle] bundleIdentifier]; + return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCocoaPluginIdentifier] || + [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCarbonPluginIdentifier] || + [[path lastPathComponent] _webkit_isCaseInsensitiveEqualToString:JavaCFMPluginFilename]; +} + +- (BOOL)isNativeLibraryData:(NSData *)data +{ + // If we have a 32-bit thin Mach-O file, see if we have an i386 binary. If not, don't load it. + // This is designed to be the safest possible test for now. We'll only reject files that we + // can easily tell are wrong. + if ([data length] >= sizeof(struct mach_header)) { + const NXArchInfo *localArch = NXGetLocalArchInfo(); + if (localArch != NULL) { + struct mach_header *header = (struct mach_header *)[data bytes]; + if (header->magic == MH_MAGIC) + return (header->cputype == localArch->cputype); + if (header->magic == MH_CIGAM) + return ((cpu_type_t) OSSwapInt32(header->cputype) == localArch->cputype); + } + } + return YES; +} + +- (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database +{ + if (!pluginDatabases) + pluginDatabases = [[NSMutableSet alloc] init]; + + ASSERT(![pluginDatabases containsObject:database]); + [pluginDatabases addObject:database]; +} + +- (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database +{ + ASSERT(pluginDatabases); + ASSERT([pluginDatabases containsObject:database]); + + [pluginDatabases removeObject:database]; +} + +@end + +@implementation NSArray (WebPluginExtensions) + +- (NSArray *)_web_lowercaseStrings +{ + NSMutableArray *lowercaseStrings = [NSMutableArray arrayWithCapacity:[self count]]; + NSEnumerator *strings = [self objectEnumerator]; + NSString *string; + + while ((string = [strings nextObject]) != nil) { + if ([string isKindOfClass:[NSString class]]) + [lowercaseStrings addObject:[string lowercaseString]]; + } + + return lowercaseStrings; +} + +@end