WebBasePluginPackage.mm 16 KB

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