2 * Copyright (C) 2005 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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 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.
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.
29 #import <WebKitLegacy/WebBasePluginPackage.h>
32 #import <WebCore/WebCoreObjCExtras.h>
33 #import <WebKitLegacy/WebKitNSStringExtras.h>
34 #import <WebKitLegacy/WebNetscapePluginPackage.h>
35 #import <WebKitLegacy/WebPluginPackage.h>
36 #import <runtime/InitializeThreading.h>
37 #import <wtf/Assertions.h>
38 #import <wtf/MainThread.h>
39 #import <wtf/ObjcRuntimeExtras.h>
40 #import <wtf/RunLoop.h>
41 #import <wtf/Vector.h>
42 #import <wtf/text/CString.h>
44 #import <WebKitSystemInterface.h>
46 #import "WebKitLogging.h"
47 #import "WebTypesInternal.h"
49 #import <mach-o/arch.h>
50 #import <mach-o/fat.h>
51 #import <mach-o/loader.h>
53 #define JavaCocoaPluginIdentifier "com.apple.JavaPluginCocoa"
54 #define JavaCarbonPluginIdentifier "com.apple.JavaAppletPlugin"
56 #define QuickTimeCarbonPluginIdentifier "com.apple.QuickTime Plugin.plugin"
57 #define QuickTimeCocoaPluginIdentifier "com.apple.quicktime.webplugin"
59 @interface NSArray (WebPluginExtensions)
60 - (NSArray *)_web_lowercaseStrings;
63 using namespace WebCore;
65 @implementation WebBasePluginPackage
70 JSC::initializeThreading();
71 WTF::initializeMainThreadToProcessMainThread();
72 RunLoop::initializeMainRunLoop();
74 WebCoreObjCFinalizeOnMainThread(self);
77 + (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath
80 WebBasePluginPackage *pluginPackage = [[WebPluginPackage alloc] initWithPath:pluginPath];
83 #if ENABLE(NETSCAPE_PLUGIN_API)
84 pluginPackage = [[WebNetscapePluginPackage alloc] initWithPath:pluginPath];
90 return [pluginPackage autorelease];
93 + (NSString *)preferredLocalizationName
95 return CFBridgingRelease(WKCopyCFLocalizationPreferredName(NULL));
99 #pragma clang diagnostic push
100 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
102 // FIXME: Rewrite this in terms of -[NSURL URLByResolvingBookmarkData:…].
103 static NSString *pathByResolvingSymlinksAndAliases(NSString *thePath)
105 NSString *newPath = [thePath stringByResolvingSymlinksInPath];
111 err = FSPathMakeRef((const UInt8 *)[thePath fileSystemRepresentation], &fref, NULL);
115 Boolean targetIsFolder;
117 err = FSResolveAliasFileWithMountFlags(&fref, TRUE, &targetIsFolder, &wasAliased, kResolveAliasFileNoUI);
122 CFURLRef URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fref);
123 newPath = [(NSURL *)URL path];
131 #pragma clang diagnostic pop
134 - (id)initWithPath:(NSString *)pluginPath
136 if (!(self = [super init]))
139 path = pathByResolvingSymlinksAndAliases(pluginPath);
140 cfBundle = adoptCF(CFBundleCreate(kCFAllocatorDefault, (CFURLRef)[NSURL fileURLWithPath:path]));
154 - (void)createPropertyListFile
156 if ([self load] && BP_CreatePluginMIMETypesPreferences) {
157 BP_CreatePluginMIMETypesPreferences();
162 - (NSDictionary *)pListForPath:(NSString *)pListPath createFile:(BOOL)createFile
165 [self createPropertyListFile];
167 NSDictionary *pList = nil;
168 NSData *data = [NSData dataWithContentsOfFile:pListPath];
170 pList = [NSPropertyListSerialization propertyListWithData:data options:kCFPropertyListImmutable format:nil error:nil];
175 - (id)_objectForInfoDictionaryKey:(NSString *)key
177 CFDictionaryRef bundleInfoDictionary = CFBundleGetInfoDictionary(cfBundle.get());
178 if (!bundleInfoDictionary)
181 return (id)CFDictionaryGetValue(bundleInfoDictionary, key);
184 - (BOOL)getPluginInfoFromPLists
189 NSDictionary *MIMETypes = nil;
190 NSString *pListFilename = [self _objectForInfoDictionaryKey:WebPluginMIMETypesFilenameKey];
192 // Check if the MIME types are claimed in a plist in the user's preferences directory.
194 NSString *pListPath = [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), pListFilename];
195 NSDictionary *pList = [self pListForPath:pListPath createFile:NO];
197 // If the plist isn't localized, have the plug-in recreate it in the preferred language.
198 NSString *localizationName = [pList objectForKey:WebPluginLocalizationNameKey];
199 if (![localizationName isEqualToString:[[self class] preferredLocalizationName]])
200 pList = [self pListForPath:pListPath createFile:YES];
201 MIMETypes = [pList objectForKey:WebPluginMIMETypesKey];
203 // Plist doesn't exist, ask the plug-in to create it.
204 MIMETypes = [[self pListForPath:pListPath createFile:YES] objectForKey:WebPluginMIMETypesKey];
208 MIMETypes = [self _objectForInfoDictionaryKey:WebPluginMIMETypesKey];
213 NSEnumerator *keyEnumerator = [MIMETypes keyEnumerator];
214 NSDictionary *MIMEDictionary;
217 while ((MIME = [keyEnumerator nextObject]) != nil) {
218 MIMEDictionary = [MIMETypes objectForKey:MIME];
220 // FIXME: Consider storing disabled MIME types.
221 NSNumber *isEnabled = [MIMEDictionary objectForKey:WebPluginTypeEnabledKey];
222 if (isEnabled && [isEnabled boolValue] == NO)
225 MimeClassInfo mimeClassInfo;
227 NSArray *extensions = [[MIMEDictionary objectForKey:WebPluginExtensionsKey] _web_lowercaseStrings];
228 for (NSUInteger i = 0; i < [extensions count]; ++i) {
229 // The DivX plug-in lists multiple extensions in a comma separated string instead of using
230 // multiple array elements in the property list. Work around this here by splitting the
231 // extension string into components.
232 NSArray *extensionComponents = [[extensions objectAtIndex:i] componentsSeparatedByString:@","];
234 for (NSString *extension in extensionComponents)
235 mimeClassInfo.extensions.append(extension);
238 mimeClassInfo.type = String(MIME).lower();
240 mimeClassInfo.desc = [MIMEDictionary objectForKey:WebPluginTypeDescriptionKey];
242 pluginInfo.mimes.append(mimeClassInfo);
245 NSString *filename = [(NSString *)path lastPathComponent];
246 pluginInfo.file = filename;
248 NSString *theName = [self _objectForInfoDictionaryKey:WebPluginNameKey];
251 pluginInfo.name = theName;
253 NSString *description = [self _objectForInfoDictionaryKey:WebPluginDescriptionKey];
255 description = filename;
256 pluginInfo.desc = description;
258 pluginInfo.isApplicationPlugin = false;
265 if (cfBundle && !BP_CreatePluginMIMETypesPreferences)
266 BP_CreatePluginMIMETypesPreferences = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("BP_CreatePluginMIMETypesPreferences"));
273 ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
274 [pluginDatabases release];
281 ASSERT_MAIN_THREAD();
282 ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
283 [pluginDatabases release];
288 - (const String&)path
293 - (const PluginInfo&)pluginInfo
298 - (BOOL)supportsExtension:(const String&)extension
300 ASSERT(extension.lower() == extension);
302 for (size_t i = 0; i < pluginInfo.mimes.size(); ++i) {
303 const Vector<String>& extensions = pluginInfo.mimes[i].extensions;
305 if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end())
312 - (BOOL)supportsMIMEType:(const WTF::String&)mimeType
314 ASSERT(mimeType.lower() == mimeType);
316 for (size_t i = 0; i < pluginInfo.mimes.size(); ++i) {
317 if (pluginInfo.mimes[i].type == mimeType)
324 - (NSString *)MIMETypeForExtension:(const String&)extension
326 ASSERT(extension.lower() == extension);
328 for (size_t i = 0; i < pluginInfo.mimes.size(); ++i) {
329 const MimeClassInfo& mimeClassInfo = pluginInfo.mimes[i];
330 const Vector<String>& extensions = mimeClassInfo.extensions;
332 if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end())
333 return mimeClassInfo.type;
339 - (BOOL)isQuickTimePlugIn
341 const String& bundleIdentifier = [self bundleIdentifier];
342 return bundleIdentifier == QuickTimeCocoaPluginIdentifier || bundleIdentifier == QuickTimeCocoaPluginIdentifier;
347 const String& bundleIdentifier = [self bundleIdentifier];
348 return bundleIdentifier == JavaCocoaPluginIdentifier || bundleIdentifier == JavaCarbonPluginIdentifier;
351 static inline void swapIntsInHeader(uint32_t* rawData, size_t length)
353 for (size_t i = 0; i < length; ++i)
354 rawData[i] = OSSwapInt32(rawData[i]);
357 - (BOOL)isNativeLibraryData:(NSData *)data
359 NSUInteger sizeInBytes = [data length];
360 Vector<uint32_t, 128> rawData((sizeInBytes + 3) / 4);
361 memcpy(rawData.data(), [data bytes], sizeInBytes);
363 unsigned numArchs = 0;
364 struct fat_arch singleArch = { 0, 0, 0, 0, 0 };
365 struct fat_arch* archs = 0;
367 if (sizeInBytes >= sizeof(struct mach_header_64)) {
368 uint32_t magic = *rawData.data();
370 if (magic == MH_MAGIC || magic == MH_CIGAM) {
371 // We have a 32-bit thin binary
372 struct mach_header* header = (struct mach_header*)rawData.data();
374 // Check if we need to swap the bytes
375 if (magic == MH_CIGAM)
376 swapIntsInHeader(rawData.data(), rawData.size());
378 singleArch.cputype = header->cputype;
379 singleArch.cpusubtype = header->cpusubtype;
383 } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
384 // We have a 64-bit thin binary
385 struct mach_header_64* header = (struct mach_header_64*)rawData.data();
387 // Check if we need to swap the bytes
388 if (magic == MH_CIGAM_64)
389 swapIntsInHeader(rawData.data(), rawData.size());
391 singleArch.cputype = header->cputype;
392 singleArch.cpusubtype = header->cpusubtype;
396 } else if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
397 // We have a fat (universal) binary
399 // Check if we need to swap the bytes
400 if (magic == FAT_CIGAM)
401 swapIntsInHeader(rawData.data(), rawData.size());
403 COMPILE_ASSERT(sizeof(struct fat_header) % sizeof(uint32_t) == 0, struct_fat_header_must_be_integral_size_of_uint32_t);
404 archs = reinterpret_cast<struct fat_arch*>(rawData.data() + sizeof(struct fat_header) / sizeof(uint32_t));
405 numArchs = reinterpret_cast<struct fat_header*>(rawData.data())->nfat_arch;
407 unsigned maxArchs = (sizeInBytes - sizeof(struct fat_header)) / sizeof(struct fat_arch);
408 if (numArchs > maxArchs)
413 if (!archs || !numArchs)
416 const NXArchInfo* localArch = NXGetLocalArchInfo();
420 cpu_type_t cputype = localArch->cputype;
421 cpu_subtype_t cpusubtype = localArch->cpusubtype;
424 // NXGetLocalArchInfo returns CPU_TYPE_X86 even when running in 64-bit.
425 // See <rdar://problem/4996965> for more information.
426 cputype = CPU_TYPE_X86_64;
429 return NXFindBestFatArch(cputype, cpusubtype, archs, numArchs) != 0;
432 - (UInt32)versionNumber
434 // CFBundleGetVersionNumber doesn't work with all possible versioning schemes, but we think for now it's good enough for us.
435 return CFBundleGetVersionNumber(cfBundle.get());
438 - (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database
440 if (!pluginDatabases)
441 pluginDatabases = [[NSMutableSet alloc] init];
443 ASSERT(![pluginDatabases containsObject:database]);
444 [pluginDatabases addObject:database];
447 - (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
449 ASSERT(pluginDatabases);
450 ASSERT([pluginDatabases containsObject:database]);
452 [pluginDatabases removeObject:database];
455 - (String)bundleIdentifier
457 return CFBundleGetIdentifier(cfBundle.get());
460 - (String)bundleVersion
462 CFDictionaryRef infoDictionary = CFBundleGetInfoDictionary(cfBundle.get());
466 CFTypeRef bundleVersionString = CFDictionaryGetValue(infoDictionary, kCFBundleVersionKey);
467 if (!bundleVersionString || CFGetTypeID(bundleVersionString) != CFStringGetTypeID())
470 return reinterpret_cast<CFStringRef>(bundleVersionString);
475 @implementation NSArray (WebPluginExtensions)
477 - (NSArray *)_web_lowercaseStrings
479 NSMutableArray *lowercaseStrings = [NSMutableArray arrayWithCapacity:[self count]];
480 NSEnumerator *strings = [self objectEnumerator];
483 while ((string = [strings nextObject]) != nil) {
484 if ([string isKindOfClass:[NSString class]])
485 [lowercaseStrings addObject:[string lowercaseString]];
488 return lowercaseStrings;