WebKit/mac/Plugins/WebBasePluginPackage.mm
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 <algorithm>
       
    32 #import <WebCore/WebCoreObjCExtras.h>
       
    33 #import <WebKit/WebKitNSStringExtras.h>
       
    34 #import <WebKit/WebNSObjectExtras.h>
       
    35 #import <WebKit/WebNetscapePluginPackage.h>
       
    36 #import <WebKit/WebPluginPackage.h>
       
    37 #import <runtime/InitializeThreading.h>
       
    38 #import <wtf/Assertions.h>
       
    39 #import <wtf/Threading.h>
       
    40 #import <wtf/Vector.h>
       
    41 
       
    42 #import <WebKitSystemInterface.h>
       
    43 
       
    44 #import "WebKitLogging.h"
       
    45 #import "WebTypesInternal.h"
       
    46 
       
    47 #import <mach-o/arch.h>
       
    48 #import <mach-o/fat.h>
       
    49 #import <mach-o/loader.h>
       
    50 
       
    51 #define JavaCocoaPluginIdentifier   "com.apple.JavaPluginCocoa"
       
    52 #define JavaCarbonPluginIdentifier  "com.apple.JavaAppletPlugin"
       
    53 #define JavaCFMPluginFilename       "Java Applet Plugin Enabler"
       
    54 
       
    55 #define QuickTimeCarbonPluginIdentifier       "com.apple.QuickTime Plugin.plugin"
       
    56 #define QuickTimeCocoaPluginIdentifier        "com.apple.quicktime.webplugin"
       
    57 
       
    58 @interface NSArray (WebPluginExtensions)
       
    59 - (NSArray *)_web_lowercaseStrings;
       
    60 @end;
       
    61 
       
    62 using namespace std;
       
    63 using namespace WebCore;
       
    64 
       
    65 @implementation WebBasePluginPackage
       
    66 
       
    67 + (void)initialize
       
    68 {
       
    69     JSC::initializeThreading();
       
    70     WTF::initializeMainThreadToProcessMainThread();
       
    71 #ifndef BUILDING_ON_TIGER
       
    72     WebCoreObjCFinalizeOnMainThread(self);
       
    73 #endif
       
    74 }
       
    75 
       
    76 + (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath
       
    77 {
       
    78     
       
    79     WebBasePluginPackage *pluginPackage = [[WebPluginPackage alloc] initWithPath:pluginPath];
       
    80 
       
    81     if (!pluginPackage) {
       
    82 #if ENABLE(NETSCAPE_PLUGIN_API)
       
    83         pluginPackage = [[WebNetscapePluginPackage alloc] initWithPath:pluginPath];
       
    84 #else
       
    85         return nil;
       
    86 #endif
       
    87     }
       
    88 
       
    89     return [pluginPackage autorelease];
       
    90 }
       
    91 
       
    92 + (NSString *)preferredLocalizationName
       
    93 {
       
    94     return WebCFAutorelease(WKCopyCFLocalizationPreferredName(NULL));
       
    95 }
       
    96 
       
    97 static NSString *pathByResolvingSymlinksAndAliases(NSString *thePath)
       
    98 {
       
    99     NSString *newPath = [thePath stringByResolvingSymlinksInPath];
       
   100 
       
   101     FSRef fref;
       
   102     OSStatus err;
       
   103 
       
   104     err = FSPathMakeRef((const UInt8 *)[thePath fileSystemRepresentation], &fref, NULL);
       
   105     if (err != noErr)
       
   106         return newPath;
       
   107 
       
   108     Boolean targetIsFolder;
       
   109     Boolean wasAliased;
       
   110     err = FSResolveAliasFileWithMountFlags(&fref, TRUE, &targetIsFolder, &wasAliased, kResolveAliasFileNoUI);
       
   111     if (err != noErr)
       
   112         return newPath;
       
   113 
       
   114     if (wasAliased) {
       
   115         CFURLRef URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fref);
       
   116         newPath = [(NSURL *)URL path];
       
   117         CFRelease(URL);
       
   118     }
       
   119 
       
   120     return newPath;
       
   121 }
       
   122 
       
   123 - (id)initWithPath:(NSString *)pluginPath
       
   124 {
       
   125     if (!(self = [super init]))
       
   126         return nil;
       
   127         
       
   128     path = pathByResolvingSymlinksAndAliases(pluginPath);
       
   129     cfBundle.adoptCF(CFBundleCreate(kCFAllocatorDefault, (CFURLRef)[NSURL fileURLWithPath:path]));
       
   130 
       
   131 #ifndef __ppc__
       
   132     // 32-bit PowerPC is the only platform where non-bundled CFM plugins are supported
       
   133     if (!cfBundle) {
       
   134         [self release];
       
   135         return nil;
       
   136     }
       
   137 #endif
       
   138     
       
   139     return self;
       
   140 }
       
   141 
       
   142 - (void)unload
       
   143 {
       
   144 }
       
   145 
       
   146 - (void)createPropertyListFile
       
   147 {
       
   148     if ([self load] && BP_CreatePluginMIMETypesPreferences) {
       
   149         BP_CreatePluginMIMETypesPreferences();
       
   150         [self unload];
       
   151     }
       
   152 }
       
   153 
       
   154 - (NSDictionary *)pListForPath:(NSString *)pListPath createFile:(BOOL)createFile
       
   155 {
       
   156     if (createFile)
       
   157         [self createPropertyListFile];
       
   158     
       
   159     NSDictionary *pList = nil;
       
   160     NSData *data = [NSData dataWithContentsOfFile:pListPath];
       
   161     if (data) {
       
   162         pList = [NSPropertyListSerialization propertyListFromData:data
       
   163                                                  mutabilityOption:NSPropertyListImmutable
       
   164                                                            format:nil
       
   165                                                  errorDescription:nil];
       
   166     }
       
   167     
       
   168     return pList;
       
   169 }
       
   170 
       
   171 - (id)_objectForInfoDictionaryKey:(NSString *)key
       
   172 {
       
   173     CFDictionaryRef bundleInfoDictionary = CFBundleGetInfoDictionary(cfBundle.get());
       
   174     if (!bundleInfoDictionary)
       
   175         return nil;
       
   176 
       
   177     return (id)CFDictionaryGetValue(bundleInfoDictionary, key);
       
   178 }
       
   179 
       
   180 - (BOOL)getPluginInfoFromPLists
       
   181 {
       
   182     if (!cfBundle)
       
   183         return NO;
       
   184     
       
   185     NSDictionary *MIMETypes = nil;
       
   186     NSString *pListFilename = [self _objectForInfoDictionaryKey:WebPluginMIMETypesFilenameKey];
       
   187     
       
   188     // Check if the MIME types are claimed in a plist in the user's preferences directory.
       
   189     if (pListFilename) {
       
   190         NSString *pListPath = [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), pListFilename];
       
   191         NSDictionary *pList = [self pListForPath:pListPath createFile:NO];
       
   192         if (pList) {
       
   193             // If the plist isn't localized, have the plug-in recreate it in the preferred language.
       
   194             NSString *localizationName = [pList objectForKey:WebPluginLocalizationNameKey];
       
   195             if (![localizationName isEqualToString:[[self class] preferredLocalizationName]])
       
   196                 pList = [self pListForPath:pListPath createFile:YES];
       
   197             MIMETypes = [pList objectForKey:WebPluginMIMETypesKey];
       
   198         } else
       
   199             // Plist doesn't exist, ask the plug-in to create it.
       
   200             MIMETypes = [[self pListForPath:pListPath createFile:YES] objectForKey:WebPluginMIMETypesKey];
       
   201     }
       
   202 
       
   203     if (!MIMETypes) {
       
   204         MIMETypes = [self _objectForInfoDictionaryKey:WebPluginMIMETypesKey];
       
   205         if (!MIMETypes)
       
   206             return NO;
       
   207     }
       
   208 
       
   209     NSEnumerator *keyEnumerator = [MIMETypes keyEnumerator];
       
   210     NSDictionary *MIMEDictionary;
       
   211     NSString *MIME, *description;
       
   212     NSArray *extensions;
       
   213 
       
   214     while ((MIME = [keyEnumerator nextObject]) != nil) {
       
   215         MIMEDictionary = [MIMETypes objectForKey:MIME];
       
   216         
       
   217         // FIXME: Consider storing disabled MIME types.
       
   218         NSNumber *isEnabled = [MIMEDictionary objectForKey:WebPluginTypeEnabledKey];
       
   219         if (isEnabled && [isEnabled boolValue] == NO)
       
   220             continue;
       
   221 
       
   222         MimeClassInfo mimeClassInfo;
       
   223         
       
   224         extensions = [[MIMEDictionary objectForKey:WebPluginExtensionsKey] _web_lowercaseStrings];
       
   225         for (NSUInteger i = 0; i < [extensions count]; ++i)
       
   226             mimeClassInfo.extensions.append((NSString *)[extensions objectAtIndex:i]);
       
   227 
       
   228         if ([extensions count] == 0)
       
   229             extensions = [NSArray arrayWithObject:@""];
       
   230 
       
   231         mimeClassInfo.type = String(MIME).lower();
       
   232 
       
   233         description = [MIMEDictionary objectForKey:WebPluginTypeDescriptionKey];
       
   234         mimeClassInfo.desc = description;
       
   235 
       
   236         pluginInfo.mimes.append(mimeClassInfo);
       
   237         if (!description)
       
   238             description = @"";
       
   239     }
       
   240 
       
   241     NSString *filename = [(NSString *)path lastPathComponent];
       
   242     pluginInfo.file = filename;
       
   243 
       
   244     NSString *theName = [self _objectForInfoDictionaryKey:WebPluginNameKey];
       
   245     if (!theName)
       
   246         theName = filename;
       
   247     pluginInfo.name = theName;
       
   248 
       
   249     description = [self _objectForInfoDictionaryKey:WebPluginDescriptionKey];
       
   250     if (!description)
       
   251         description = filename;
       
   252     pluginInfo.desc = description;
       
   253 
       
   254     return YES;
       
   255 }
       
   256 
       
   257 - (BOOL)load
       
   258 {
       
   259     if (cfBundle && !BP_CreatePluginMIMETypesPreferences)
       
   260         BP_CreatePluginMIMETypesPreferences = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("BP_CreatePluginMIMETypesPreferences"));
       
   261     
       
   262     return YES;
       
   263 }
       
   264 
       
   265 - (void)dealloc
       
   266 {
       
   267     ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
       
   268     [pluginDatabases release];
       
   269     
       
   270     [super dealloc];
       
   271 }
       
   272 
       
   273 - (void)finalize
       
   274 {
       
   275     ASSERT_MAIN_THREAD();
       
   276     ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
       
   277     [pluginDatabases release];
       
   278 
       
   279     [super finalize];
       
   280 }
       
   281 
       
   282 - (const String&)path
       
   283 {
       
   284     return path;
       
   285 }
       
   286 
       
   287 - (const PluginInfo&)pluginInfo
       
   288 {
       
   289     return pluginInfo;
       
   290 }
       
   291 
       
   292 - (BOOL)supportsExtension:(const String&)extension
       
   293 {
       
   294     ASSERT(extension.lower() == extension);
       
   295     
       
   296     for (size_t i = 0; i < pluginInfo.mimes.size(); ++i) {
       
   297         const Vector<String>& extensions = pluginInfo.mimes[i].extensions;
       
   298 
       
   299         if (find(extensions.begin(), extensions.end(), extension) != extensions.end())
       
   300             return YES;
       
   301     }
       
   302 
       
   303     return NO;
       
   304 }
       
   305 
       
   306 - (BOOL)supportsMIMEType:(const WebCore::String&)mimeType
       
   307 {
       
   308     ASSERT(mimeType.lower() == mimeType);
       
   309     
       
   310     for (size_t i = 0; i < pluginInfo.mimes.size(); ++i) {
       
   311         if (pluginInfo.mimes[i].type == mimeType)
       
   312             return YES;
       
   313     }
       
   314     
       
   315     return NO;
       
   316 }
       
   317 
       
   318 - (NSString *)MIMETypeForExtension:(const String&)extension
       
   319 {
       
   320     ASSERT(extension.lower() == extension);
       
   321     
       
   322     for (size_t i = 0; i < pluginInfo.mimes.size(); ++i) {
       
   323         const MimeClassInfo& mimeClassInfo = pluginInfo.mimes[i];
       
   324         const Vector<String>& extensions = mimeClassInfo.extensions;
       
   325 
       
   326         if (find(extensions.begin(), extensions.end(), extension) != extensions.end())
       
   327             return mimeClassInfo.type;
       
   328     }
       
   329 
       
   330     return nil;
       
   331 }
       
   332 
       
   333 - (BOOL)isQuickTimePlugIn
       
   334 {
       
   335     const String& bundleIdentifier = [self bundleIdentifier];
       
   336     return bundleIdentifier == QuickTimeCocoaPluginIdentifier || bundleIdentifier == QuickTimeCocoaPluginIdentifier;
       
   337 }
       
   338 
       
   339 - (BOOL)isJavaPlugIn
       
   340 {
       
   341     const String& bundleIdentifier = [self bundleIdentifier];
       
   342     return bundleIdentifier == JavaCocoaPluginIdentifier || bundleIdentifier == JavaCarbonPluginIdentifier ||
       
   343         equalIgnoringCase(pluginInfo.file, JavaCFMPluginFilename);
       
   344 }
       
   345 
       
   346 static inline void swapIntsInHeader(uint8_t* bytes, unsigned length)
       
   347 {
       
   348     for (unsigned i = 0; i < length; i += 4) 
       
   349         *(uint32_t*)(bytes + i) = OSSwapInt32(*(uint32_t *)(bytes + i));
       
   350 }
       
   351 
       
   352 - (BOOL)isNativeLibraryData:(NSData *)data
       
   353 {
       
   354     Vector<uint8_t, 512> bytes([data length]);
       
   355     memcpy(bytes.data(), [data bytes], bytes.size());
       
   356     
       
   357     unsigned numArchs = 0;
       
   358     struct fat_arch singleArch = { 0, 0, 0, 0, 0 };
       
   359     struct fat_arch* archs = 0;
       
   360        
       
   361     if (bytes.size() >= sizeof(struct mach_header_64)) {
       
   362         uint32_t magic = *reinterpret_cast<uint32_t*>(bytes.data());
       
   363         
       
   364         if (magic == MH_MAGIC || magic == MH_CIGAM) {
       
   365             // We have a 32-bit thin binary
       
   366             struct mach_header* header = (struct mach_header*)bytes.data();
       
   367 
       
   368             // Check if we need to swap the bytes
       
   369             if (magic == MH_CIGAM)
       
   370                 swapIntsInHeader(bytes.data(), bytes.size());
       
   371     
       
   372             singleArch.cputype = header->cputype;
       
   373             singleArch.cpusubtype = header->cpusubtype;
       
   374 
       
   375             archs = &singleArch;
       
   376             numArchs = 1;
       
   377         } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
       
   378             // We have a 64-bit thin binary
       
   379             struct mach_header_64* header = (struct mach_header_64*)bytes.data();
       
   380 
       
   381             // Check if we need to swap the bytes
       
   382             if (magic == MH_CIGAM_64)
       
   383                 swapIntsInHeader(bytes.data(), bytes.size());
       
   384             
       
   385             singleArch.cputype = header->cputype;
       
   386             singleArch.cpusubtype = header->cpusubtype;
       
   387             
       
   388             archs = &singleArch;
       
   389             numArchs = 1;
       
   390         } else if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
       
   391             // We have a fat (universal) binary
       
   392 
       
   393             // Check if we need to swap the bytes
       
   394             if (magic == FAT_CIGAM)
       
   395                 swapIntsInHeader(bytes.data(), bytes.size());
       
   396             
       
   397             archs = (struct fat_arch*)(bytes.data() + sizeof(struct fat_header));            
       
   398             numArchs = ((struct fat_header *)bytes.data())->nfat_arch;
       
   399             
       
   400             unsigned maxArchs = (bytes.size() - sizeof(struct fat_header)) / sizeof(struct fat_arch);
       
   401             if (numArchs > maxArchs)
       
   402                 numArchs = maxArchs;
       
   403         }            
       
   404     }
       
   405     
       
   406     if (!archs || !numArchs)
       
   407         return NO;
       
   408     
       
   409     const NXArchInfo* localArch = NXGetLocalArchInfo();
       
   410     if (!localArch)
       
   411         return NO;
       
   412     
       
   413     cpu_type_t cputype = localArch->cputype;
       
   414     cpu_subtype_t cpusubtype = localArch->cpusubtype;
       
   415     
       
   416 #ifdef __x86_64__
       
   417     // NXGetLocalArchInfo returns CPU_TYPE_X86 even when running in 64-bit. 
       
   418     // See <rdar://problem/4996965> for more information.
       
   419     cputype = CPU_TYPE_X86_64;
       
   420 #endif
       
   421     
       
   422     return NXFindBestFatArch(cputype, cpusubtype, archs, numArchs) != 0;
       
   423 }
       
   424 
       
   425 - (UInt32)versionNumber
       
   426 {
       
   427     // CFBundleGetVersionNumber doesn't work with all possible versioning schemes, but we think for now it's good enough for us.
       
   428     return CFBundleGetVersionNumber(cfBundle.get());
       
   429 }
       
   430 
       
   431 - (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database
       
   432 {    
       
   433     if (!pluginDatabases)
       
   434         pluginDatabases = [[NSMutableSet alloc] init];
       
   435         
       
   436     ASSERT(![pluginDatabases containsObject:database]);
       
   437     [pluginDatabases addObject:database];
       
   438 }
       
   439 
       
   440 - (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
       
   441 {
       
   442     ASSERT(pluginDatabases);
       
   443     ASSERT([pluginDatabases containsObject:database]);
       
   444 
       
   445     [pluginDatabases removeObject:database];
       
   446 }
       
   447 
       
   448 - (WebCore::String)bundleIdentifier
       
   449 {
       
   450     return CFBundleGetIdentifier(cfBundle.get());
       
   451 }
       
   452 
       
   453 @end
       
   454 
       
   455 @implementation NSArray (WebPluginExtensions)
       
   456 
       
   457 - (NSArray *)_web_lowercaseStrings
       
   458 {
       
   459     NSMutableArray *lowercaseStrings = [NSMutableArray arrayWithCapacity:[self count]];
       
   460     NSEnumerator *strings = [self objectEnumerator];
       
   461     NSString *string;
       
   462 
       
   463     while ((string = [strings nextObject]) != nil) {
       
   464         if ([string isKindOfClass:[NSString class]])
       
   465             [lowercaseStrings addObject:[string lowercaseString]];
       
   466     }
       
   467 
       
   468     return lowercaseStrings;
       
   469 }
       
   470 
       
   471 @end