webengine/osswebengine/WebKit/Plugins/WebBasePluginPackage.m
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #import <WebKit/WebBasePluginPackage.h>
       
    30 
       
    31 #import <JavaScriptCore/Assertions.h>
       
    32 #import <WebKit/WebKitNSStringExtras.h>
       
    33 #import <WebKit/WebNetscapePluginPackage.h>
       
    34 #import <WebKit/WebNSObjectExtras.h>
       
    35 #import <WebKit/WebPluginPackage.h>
       
    36 #import <WebCore/WebCoreObjCExtras.h>
       
    37 
       
    38 #import <WebKitSystemInterface.h>
       
    39 
       
    40 #import "WebKitLogging.h"
       
    41 #import "WebTypesInternal.h"
       
    42 
       
    43 #import <mach-o/arch.h>
       
    44 #import <mach-o/loader.h>
       
    45 
       
    46 #define JavaCocoaPluginIdentifier   @"com.apple.JavaPluginCocoa"
       
    47 #define JavaCarbonPluginIdentifier  @"com.apple.JavaAppletPlugin"
       
    48 #define JavaCFMPluginFilename       @"Java Applet Plugin Enabler"
       
    49 
       
    50 #define QuickTimeCarbonPluginIdentifier       @"com.apple.QuickTime Plugin.plugin"
       
    51 #define QuickTimeCocoaPluginIdentifier        @"com.apple.quicktime.webplugin"
       
    52 
       
    53 @interface NSArray (WebPluginExtensions)
       
    54 - (NSArray *)_web_lowercaseStrings;
       
    55 @end;
       
    56 
       
    57 @implementation WebBasePluginPackage
       
    58 
       
    59 #ifndef BUILDING_ON_TIGER
       
    60 + (void)initialize
       
    61 {
       
    62     WebCoreObjCFinalizeOnMainThread(self);
       
    63 }
       
    64 #endif
       
    65 
       
    66 + (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath
       
    67 {
       
    68     
       
    69     WebBasePluginPackage *pluginPackage = [[WebPluginPackage alloc] initWithPath:pluginPath];
       
    70 
       
    71     if (!pluginPackage) {
       
    72 #ifdef __LP64__
       
    73         return nil;
       
    74 #else
       
    75         pluginPackage = [[WebNetscapePluginPackage alloc] initWithPath:pluginPath];
       
    76 #endif
       
    77     }
       
    78 
       
    79     return [pluginPackage autorelease];
       
    80 }
       
    81 
       
    82 + (NSString *)preferredLocalizationName
       
    83 {
       
    84     return WebCFAutorelease(WKCopyCFLocalizationPreferredName(NULL));
       
    85 }
       
    86 
       
    87 - (NSString *)pathByResolvingSymlinksAndAliasesInPath:(NSString *)thePath
       
    88 {
       
    89     NSString *newPath = [thePath stringByResolvingSymlinksInPath];
       
    90 
       
    91     FSRef fref;
       
    92     OSStatus err;
       
    93 
       
    94     err = FSPathMakeRef((const UInt8 *)[thePath fileSystemRepresentation], &fref, NULL);
       
    95     if (err != noErr)
       
    96         return newPath;
       
    97 
       
    98     Boolean targetIsFolder;
       
    99     Boolean wasAliased;
       
   100     err = FSResolveAliasFileWithMountFlags(&fref, TRUE, &targetIsFolder, &wasAliased, kResolveAliasFileNoUI);
       
   101     if (err != noErr)
       
   102         return newPath;
       
   103 
       
   104     if (wasAliased) {
       
   105         CFURLRef URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fref);
       
   106         newPath = [(NSURL *)URL path];
       
   107         CFRelease(URL);
       
   108     }
       
   109 
       
   110     return newPath;
       
   111 }
       
   112 
       
   113 - (id)initWithPath:(NSString *)pluginPath
       
   114 {
       
   115     if (!(self = [super init]))
       
   116         return nil;
       
   117         
       
   118     path = [[self pathByResolvingSymlinksAndAliasesInPath:pluginPath] retain];
       
   119     bundle = [[NSBundle alloc] initWithPath:path];
       
   120 #ifndef __ppc__
       
   121     // 32-bit PowerPC is the only platform where non-bundled CFM plugins are supported
       
   122     if (!bundle) {
       
   123         [self release];
       
   124         return nil;
       
   125     }
       
   126 #endif
       
   127     cfBundle = CFBundleCreate(NULL, (CFURLRef)[NSURL fileURLWithPath:path]);
       
   128     extensionToMIME = [[NSMutableDictionary alloc] init];
       
   129     
       
   130     return self;
       
   131 }
       
   132 
       
   133 - (BOOL)getPluginInfoFromBundleAndMIMEDictionary:(NSDictionary *)MIMETypes
       
   134 {
       
   135     if (!bundle)
       
   136         return NO;
       
   137     
       
   138     if (!MIMETypes) {
       
   139         MIMETypes = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesKey];
       
   140         if (!MIMETypes)
       
   141             return NO;
       
   142     }
       
   143 
       
   144     NSMutableDictionary *MIMEToExtensionsDictionary = [NSMutableDictionary dictionary];
       
   145     NSMutableDictionary *MIMEToDescriptionDictionary = [NSMutableDictionary dictionary];
       
   146     NSEnumerator *keyEnumerator = [MIMETypes keyEnumerator];
       
   147     NSDictionary *MIMEDictionary;
       
   148     NSString *MIME, *description;
       
   149     NSArray *extensions;
       
   150 
       
   151     while ((MIME = [keyEnumerator nextObject]) != nil) {
       
   152         MIMEDictionary = [MIMETypes objectForKey:MIME];
       
   153         
       
   154         // FIXME: Consider storing disabled MIME types.
       
   155         NSNumber *isEnabled = [MIMEDictionary objectForKey:WebPluginTypeEnabledKey];
       
   156         if (isEnabled && [isEnabled boolValue] == NO)
       
   157             continue;
       
   158 
       
   159         extensions = [[MIMEDictionary objectForKey:WebPluginExtensionsKey] _web_lowercaseStrings];
       
   160         if ([extensions count] == 0)
       
   161             extensions = [NSArray arrayWithObject:@""];
       
   162 
       
   163         MIME = [MIME lowercaseString];
       
   164 
       
   165         [MIMEToExtensionsDictionary setObject:extensions forKey:MIME];
       
   166 
       
   167         description = [MIMEDictionary objectForKey:WebPluginTypeDescriptionKey];
       
   168         if (!description)
       
   169             description = @"";
       
   170 
       
   171         [MIMEToDescriptionDictionary setObject:description forKey:MIME];
       
   172     }
       
   173 
       
   174     [self setMIMEToExtensionsDictionary:MIMEToExtensionsDictionary];
       
   175     [self setMIMEToDescriptionDictionary:MIMEToDescriptionDictionary];
       
   176 
       
   177     NSString *filename = [self filename];
       
   178 
       
   179     NSString *theName = [bundle objectForInfoDictionaryKey:WebPluginNameKey];
       
   180     if (!theName)
       
   181         theName = filename;
       
   182     [self setName:theName];
       
   183 
       
   184     description = [bundle objectForInfoDictionaryKey:WebPluginDescriptionKey];
       
   185     if (!description)
       
   186         description = filename;
       
   187     [self setPluginDescription:description];
       
   188 
       
   189     return YES;
       
   190 }
       
   191 
       
   192 - (NSDictionary *)pListForPath:(NSString *)pListPath createFile:(BOOL)createFile
       
   193 {
       
   194     if (createFile && [self load] && BP_CreatePluginMIMETypesPreferences)
       
   195         BP_CreatePluginMIMETypesPreferences();
       
   196     
       
   197     NSDictionary *pList = nil;
       
   198     NSData *data = [NSData dataWithContentsOfFile:pListPath];
       
   199     if (data) {
       
   200         pList = [NSPropertyListSerialization propertyListFromData:data
       
   201                                                  mutabilityOption:NSPropertyListImmutable
       
   202                                                            format:nil
       
   203                                                  errorDescription:nil];
       
   204     }
       
   205     
       
   206     return pList;
       
   207 }
       
   208 
       
   209 - (BOOL)getPluginInfoFromPLists
       
   210 {
       
   211     if (!bundle)
       
   212         return NO;
       
   213     
       
   214     NSDictionary *MIMETypes = nil;
       
   215     NSString *pListFilename = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesFilenameKey];
       
   216     
       
   217     // Check if the MIME types are claimed in a plist in the user's preferences directory.
       
   218     if (pListFilename) {
       
   219         NSString *pListPath = [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), pListFilename];
       
   220         NSDictionary *pList = [self pListForPath:pListPath createFile:NO];
       
   221         if (pList) {
       
   222             // If the plist isn't localized, have the plug-in recreate it in the preferred language.
       
   223             NSString *localizationName = [pList objectForKey:WebPluginLocalizationNameKey];
       
   224             if (![localizationName isEqualToString:[[self class] preferredLocalizationName]])
       
   225                 pList = [self pListForPath:pListPath createFile:YES];
       
   226             MIMETypes = [pList objectForKey:WebPluginMIMETypesKey];
       
   227         } else
       
   228             // Plist doesn't exist, ask the plug-in to create it.
       
   229             MIMETypes = [[self pListForPath:pListPath createFile:YES] objectForKey:WebPluginMIMETypesKey];
       
   230     }
       
   231     
       
   232     // Pass the MIME dictionary to the superclass to parse it.
       
   233     return [self getPluginInfoFromBundleAndMIMEDictionary:MIMETypes];
       
   234 }
       
   235 
       
   236 - (BOOL)load
       
   237 {
       
   238     if (bundle && !BP_CreatePluginMIMETypesPreferences)
       
   239         BP_CreatePluginMIMETypesPreferences = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("BP_CreatePluginMIMETypesPreferences"));
       
   240     
       
   241     return YES;
       
   242 }
       
   243 
       
   244 - (void)dealloc
       
   245 {
       
   246     ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
       
   247     [pluginDatabases release];
       
   248     
       
   249     [name release];
       
   250     [path release];
       
   251     [pluginDescription release];
       
   252 
       
   253     [MIMEToDescription release];
       
   254     [MIMEToExtensions release];
       
   255     [extensionToMIME release];
       
   256 
       
   257     [bundle release];
       
   258     if (cfBundle)
       
   259         CFRelease(cfBundle);
       
   260     
       
   261     [super dealloc];
       
   262 }
       
   263 
       
   264 - (void)finalize
       
   265 {
       
   266     ASSERT_MAIN_THREAD();
       
   267     ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
       
   268     [pluginDatabases release];
       
   269 
       
   270     if (cfBundle)
       
   271         CFRelease(cfBundle);
       
   272 
       
   273     [super finalize];
       
   274 }
       
   275 
       
   276 - (NSString *)name
       
   277 {
       
   278     return name;
       
   279 }
       
   280 
       
   281 - (NSString *)path
       
   282 {
       
   283     return path;
       
   284 }
       
   285 
       
   286 - (NSString *)filename
       
   287 {
       
   288     return [path lastPathComponent];
       
   289 }
       
   290 
       
   291 - (NSString *)pluginDescription
       
   292 {
       
   293     return pluginDescription;
       
   294 }
       
   295 
       
   296 - (NSEnumerator *)extensionEnumerator
       
   297 {
       
   298     return [extensionToMIME keyEnumerator];
       
   299 }
       
   300 
       
   301 - (NSEnumerator *)MIMETypeEnumerator
       
   302 {
       
   303     return [MIMEToExtensions keyEnumerator];
       
   304 }
       
   305 
       
   306 - (NSString *)descriptionForMIMEType:(NSString *)MIMEType
       
   307 {
       
   308     return [MIMEToDescription objectForKey:MIMEType];
       
   309 }
       
   310 
       
   311 - (NSString *)MIMETypeForExtension:(NSString *)extension
       
   312 {
       
   313     return [extensionToMIME objectForKey:extension];
       
   314 }
       
   315 
       
   316 - (NSArray *)extensionsForMIMEType:(NSString *)MIMEType
       
   317 {
       
   318     return [MIMEToExtensions objectForKey:MIMEType];
       
   319 }
       
   320 
       
   321 - (NSBundle *)bundle
       
   322 {
       
   323     return bundle;
       
   324 }
       
   325 
       
   326 - (void)setName:(NSString *)theName
       
   327 {
       
   328     [name release];
       
   329     name = [theName retain];
       
   330 }
       
   331 
       
   332 - (void)setPath:(NSString *)thePath
       
   333 {
       
   334     [path release];
       
   335     path = [thePath retain];
       
   336 }
       
   337 
       
   338 - (void)setPluginDescription:(NSString *)description
       
   339 {
       
   340     [pluginDescription release];
       
   341     pluginDescription = [description retain];
       
   342 }
       
   343 
       
   344 - (void)setMIMEToDescriptionDictionary:(NSDictionary *)MIMEToDescriptionDictionary
       
   345 {
       
   346     [MIMEToDescription release];
       
   347     MIMEToDescription = [MIMEToDescriptionDictionary retain];
       
   348 }
       
   349 
       
   350 - (void)setMIMEToExtensionsDictionary:(NSDictionary *)MIMEToExtensionsDictionary
       
   351 {
       
   352     [MIMEToExtensions release];
       
   353     MIMEToExtensions = [MIMEToExtensionsDictionary retain];
       
   354 
       
   355     // Reverse the mapping
       
   356     [extensionToMIME removeAllObjects];
       
   357 
       
   358     NSEnumerator *MIMEEnumerator = [MIMEToExtensions keyEnumerator], *extensionEnumerator;
       
   359     NSString *MIME, *extension;
       
   360     NSArray *extensions;
       
   361     
       
   362     while ((MIME = [MIMEEnumerator nextObject]) != nil) {
       
   363         extensions = [MIMEToExtensions objectForKey:MIME];
       
   364         extensionEnumerator = [extensions objectEnumerator];
       
   365 
       
   366         while ((extension = [extensionEnumerator nextObject]) != nil) {
       
   367             if (![extension isEqualToString:@""])
       
   368                 [extensionToMIME setObject:MIME forKey:extension];
       
   369         }
       
   370     }
       
   371 }
       
   372 
       
   373 - (NSString *)description
       
   374 {
       
   375     return [NSString stringWithFormat:@"name: %@\npath: %@\nmimeTypes:\n%@\npluginDescription:%@",
       
   376         name, path, [MIMEToExtensions description], [MIMEToDescription description], pluginDescription];
       
   377 }
       
   378 
       
   379 - (BOOL)isQuickTimePlugIn
       
   380 {
       
   381     NSString *bundleIdentifier = [[self bundle] bundleIdentifier];
       
   382     return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCarbonPluginIdentifier] || 
       
   383         [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCocoaPluginIdentifier];
       
   384 }
       
   385 
       
   386 - (BOOL)isJavaPlugIn
       
   387 {
       
   388     NSString *bundleIdentifier = [[self bundle] bundleIdentifier];
       
   389     return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCocoaPluginIdentifier] || 
       
   390         [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCarbonPluginIdentifier] ||
       
   391         [[path lastPathComponent] _webkit_isCaseInsensitiveEqualToString:JavaCFMPluginFilename];
       
   392 }
       
   393 
       
   394 - (BOOL)isNativeLibraryData:(NSData *)data
       
   395 {  
       
   396     // If we have a 32-bit thin Mach-O file, see if we have an i386 binary.  If not, don't load it.
       
   397     // This is designed to be the safest possible test for now.  We'll only reject files that we
       
   398     // can easily tell are wrong.
       
   399     if ([data length] >= sizeof(struct mach_header)) {
       
   400         const NXArchInfo *localArch = NXGetLocalArchInfo();
       
   401         if (localArch != NULL) {
       
   402             struct mach_header *header = (struct mach_header *)[data bytes];
       
   403             if (header->magic == MH_MAGIC)
       
   404                 return (header->cputype == localArch->cputype);
       
   405             if (header->magic == MH_CIGAM)
       
   406                 return ((cpu_type_t) OSSwapInt32(header->cputype) == localArch->cputype);
       
   407         }
       
   408     }
       
   409     return YES;
       
   410 }
       
   411 
       
   412 - (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database
       
   413 {    
       
   414     if (!pluginDatabases)
       
   415         pluginDatabases = [[NSMutableSet alloc] init];
       
   416         
       
   417     ASSERT(![pluginDatabases containsObject:database]);
       
   418     [pluginDatabases addObject:database];
       
   419 }
       
   420 
       
   421 - (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
       
   422 {
       
   423     ASSERT(pluginDatabases);
       
   424     ASSERT([pluginDatabases containsObject:database]);
       
   425 
       
   426     [pluginDatabases removeObject:database];
       
   427 }
       
   428 
       
   429 @end
       
   430 
       
   431 @implementation NSArray (WebPluginExtensions)
       
   432 
       
   433 - (NSArray *)_web_lowercaseStrings
       
   434 {
       
   435     NSMutableArray *lowercaseStrings = [NSMutableArray arrayWithCapacity:[self count]];
       
   436     NSEnumerator *strings = [self objectEnumerator];
       
   437     NSString *string;
       
   438 
       
   439     while ((string = [strings nextObject]) != nil) {
       
   440         if ([string isKindOfClass:[NSString class]])
       
   441             [lowercaseStrings addObject:[string lowercaseString]];
       
   442     }
       
   443 
       
   444     return lowercaseStrings;
       
   445 }
       
   446 
       
   447 @end