/* * Copyright (C) 2005 Apple 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 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 "WebBasePluginPackage.h" #import "WebKitLogging.h" #import "WebKitNSStringExtras.h" #import "WebPluginPackage.h" #import #import #import #import #import #import #import #import #import #import #import static constexpr auto JavaCocoaPluginIdentifier ="com.apple.JavaPluginCocoa"_s; static constexpr auto JavaCarbonPluginIdentifier = "com.apple.JavaAppletPlugin"_s; static constexpr auto QuickTimeCocoaPluginIdentifier = "com.apple.quicktime.webplugin"_s; @interface NSArray (WebPluginExtensions) - (NSArray *)_web_lowercaseStrings; @end; @implementation WebBasePluginPackage + (void)initialize { #if !PLATFORM(IOS_FAMILY) JSC::initialize(); WTF::initializeMainThread(); WebCore::populateJITOperations(); #endif } + (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath { return adoptNS([[WebPluginPackage alloc] initWithPath:pluginPath]).autorelease(); } - (id)initWithPath:(NSString *)pluginPath { if (!(self = [super init])) return nil; path = [pluginPath stringByResolvingSymlinksInPath]; cfBundle = adoptCF(CFBundleCreate(kCFAllocatorDefault, (CFURLRef)[NSURL fileURLWithPath:path])); if (!cfBundle) { [self release]; return nil; } return self; } - (void)unload { } - (void)createPropertyListFile { if ([self load] && BP_CreatePluginMIMETypesPreferences) { BP_CreatePluginMIMETypesPreferences(); [self unload]; } } - (NSDictionary *)pListForPath:(NSString *)pListPath createFile:(BOOL)createFile { if (createFile) [self createPropertyListFile]; NSDictionary *pList = nil; NSData *data = [NSData dataWithContentsOfFile:pListPath]; if (data) pList = [NSPropertyListSerialization propertyListWithData:data options:kCFPropertyListImmutable format:nil error:nil]; return pList; } - (id)_objectForInfoDictionaryKey:(NSString *)key { CFDictionaryRef bundleInfoDictionary = CFBundleGetInfoDictionary(cfBundle.get()); if (!bundleInfoDictionary) return nil; return (__bridge id)CFDictionaryGetValue(bundleInfoDictionary, (__bridge CFStringRef)key); } - (BOOL)getPluginInfoFromPLists { if (!cfBundle) return NO; NSDictionary *MIMETypes = [self _objectForInfoDictionaryKey:WebPluginMIMETypesKey]; if (!MIMETypes) return NO; NSEnumerator *keyEnumerator = [MIMETypes keyEnumerator]; NSDictionary *MIMEDictionary; NSString *MIME; 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; WebCore::MimeClassInfo mimeClassInfo; NSArray *extensions = [[MIMEDictionary objectForKey:WebPluginExtensionsKey] _web_lowercaseStrings]; for (NSString *extension in extensions) { // The DivX plug-in lists multiple extensions in a comma separated string instead of using // multiple array elements in the property list. Work around this here by splitting the // extension string into components. for (NSString *component in [extension componentsSeparatedByString:@","]) mimeClassInfo.extensions.append(component); } mimeClassInfo.type = AtomString { String(MIME).convertToASCIILowercase() }; mimeClassInfo.desc = [MIMEDictionary objectForKey:WebPluginTypeDescriptionKey]; pluginInfo.mimes.append(mimeClassInfo); } NSString *filename = [(NSString *)path lastPathComponent]; pluginInfo.file = filename; NSString *theName = [self _objectForInfoDictionaryKey:WebPluginNameKey]; if (!theName) theName = filename; pluginInfo.name = theName; NSString *description = [self _objectForInfoDictionaryKey:WebPluginDescriptionKey]; if (!description) description = filename; pluginInfo.desc = description; pluginInfo.isApplicationPlugin = false; pluginInfo.clientLoadPolicy = WebCore::PluginLoadClientPolicy::Undefined; #if PLATFORM(MAC) pluginInfo.bundleIdentifier = self.bundleIdentifier; pluginInfo.versionString = self.bundleVersion; #endif return YES; } - (BOOL)load { if (cfBundle && !BP_CreatePluginMIMETypesPreferences) BP_CreatePluginMIMETypesPreferences = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("BP_CreatePluginMIMETypesPreferences")); return YES; } - (void)dealloc { ASSERT(!pluginDatabases || [pluginDatabases count] == 0); [pluginDatabases release]; [super dealloc]; } - (const String&)path { return path; } - (const WebCore::PluginInfo&)pluginInfo { return pluginInfo; } - (BOOL)supportsExtension:(const String&)extension { ASSERT(extension.convertToASCIILowercase() == extension); for (auto& entry : pluginInfo.mimes) { if (entry.extensions.contains(extension)) return YES; } return NO; } - (BOOL)supportsMIMEType:(const WTF::String&)mimeType { ASSERT(mimeType.convertToASCIILowercase() == mimeType); for (auto& entry : pluginInfo.mimes) { if (entry.type == mimeType) return YES; } return NO; } - (NSString *)MIMETypeForExtension:(const String&)extension { ASSERT(extension.convertToASCIILowercase() == extension); for (auto& entry : pluginInfo.mimes) { if (entry.extensions.contains(extension)) return entry.type; } return nil; } - (BOOL)isQuickTimePlugIn { const String& bundleIdentifier = [self bundleIdentifier]; return bundleIdentifier == QuickTimeCocoaPluginIdentifier; } - (BOOL)isJavaPlugIn { const String& bundleIdentifier = [self bundleIdentifier]; return bundleIdentifier == JavaCocoaPluginIdentifier || bundleIdentifier == JavaCarbonPluginIdentifier; } static inline void swapIntsInHeader(uint32_t* rawData, size_t length) { for (size_t i = 0; i < length; ++i) rawData[i] = OSSwapInt32(rawData[i]); } - (BOOL)isNativeLibraryData:(NSData *)data { NSUInteger sizeInBytes = [data length]; Vector rawData((sizeInBytes + 3) / 4); memcpy(rawData.data(), [data bytes], sizeInBytes); unsigned numArchs = 0; struct fat_arch singleArch = { 0, 0, 0, 0, 0 }; struct fat_arch* archs = 0; if (sizeInBytes >= sizeof(struct mach_header_64)) { uint32_t magic = *rawData.data(); if (magic == MH_MAGIC || magic == MH_CIGAM) { // We have a 32-bit thin binary struct mach_header* header = (struct mach_header*)rawData.data(); // Check if we need to swap the bytes if (magic == MH_CIGAM) swapIntsInHeader(rawData.data(), rawData.size()); singleArch.cputype = header->cputype; singleArch.cpusubtype = header->cpusubtype; archs = &singleArch; numArchs = 1; } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) { // We have a 64-bit thin binary struct mach_header_64* header = (struct mach_header_64*)rawData.data(); // Check if we need to swap the bytes if (magic == MH_CIGAM_64) swapIntsInHeader(rawData.data(), rawData.size()); singleArch.cputype = header->cputype; singleArch.cpusubtype = header->cpusubtype; archs = &singleArch; numArchs = 1; } else if (magic == FAT_MAGIC || magic == FAT_CIGAM) { // We have a fat (universal) binary // Check if we need to swap the bytes if (magic == FAT_CIGAM) swapIntsInHeader(rawData.data(), rawData.size()); static_assert(sizeof(struct fat_header) % sizeof(uint32_t) == 0, "struct fat header must be integral size of uint32_t"); archs = reinterpret_cast(rawData.data() + sizeof(struct fat_header) / sizeof(uint32_t)); numArchs = reinterpret_cast(rawData.data())->nfat_arch; unsigned maxArchs = (sizeInBytes - sizeof(struct fat_header)) / sizeof(struct fat_arch); if (numArchs > maxArchs) numArchs = maxArchs; } } if (!archs || !numArchs) return NO; ALLOW_DEPRECATED_DECLARATIONS_BEGIN const NXArchInfo* localArch = NXGetLocalArchInfo(); ALLOW_DEPRECATED_DECLARATIONS_END if (!localArch) return NO; cpu_type_t cputype = localArch->cputype; cpu_subtype_t cpusubtype = localArch->cpusubtype; #ifdef __x86_64__ // NXGetLocalArchInfo returns CPU_TYPE_X86 even when running in 64-bit. // See for more information. cputype = CPU_TYPE_X86_64; #endif ALLOW_DEPRECATED_DECLARATIONS_BEGIN return NXFindBestFatArch(cputype, cpusubtype, archs, numArchs) != 0; ALLOW_DEPRECATED_DECLARATIONS_END } - (UInt32)versionNumber { // CFBundleGetVersionNumber doesn't work with all possible versioning schemes, but we think for now it's good enough for us. return CFBundleGetVersionNumber(cfBundle.get()); } - (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]; } - (String)bundleIdentifier { return CFBundleGetIdentifier(cfBundle.get()); } - (String)bundleVersion { auto infoDictionary = CFBundleGetInfoDictionary(cfBundle.get()); if (!infoDictionary) return String(); return dynamic_cf_cast(CFDictionaryGetValue(infoDictionary, kCFBundleVersionKey)); } @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