WebNetscapePluginPackage.mm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /*
  2. * Copyright (C) 2005, 2006, 2007 Apple 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. #if ENABLE(NETSCAPE_PLUGIN_API)
  29. #import "WebNetscapePluginPackage.h"
  30. #import "WebTypesInternal.h"
  31. #import "WebKitLogging.h"
  32. #import "WebKitNSStringExtras.h"
  33. #import "WebNSFileManagerExtras.h"
  34. #import "WebNSObjectExtras.h"
  35. #import <WebCore/npruntime_impl.h>
  36. #import <wtf/RetainPtr.h>
  37. #if USE(PLUGIN_HOST_PROCESS)
  38. #import "NetscapePluginHostManager.h"
  39. using namespace WebKit;
  40. #endif
  41. using namespace WebCore;
  42. #define PluginNameOrDescriptionStringNumber 126
  43. #define MIMEDescriptionStringNumber 127
  44. #define MIMEListStringStringNumber 128
  45. @interface WebNetscapePluginPackage (Internal)
  46. - (void)_unloadWithShutdown:(BOOL)shutdown;
  47. @end
  48. @implementation WebNetscapePluginPackage
  49. - (ResFileRefNum)openResourceFile
  50. {
  51. return CFBundleOpenBundleResourceMap(cfBundle.get());
  52. }
  53. - (void)closeResourceFile:(ResFileRefNum)resRef
  54. {
  55. CFBundleCloseBundleResourceMap(cfBundle.get(), resRef);
  56. }
  57. #if COMPILER(CLANG)
  58. #pragma clang diagnostic push
  59. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  60. #endif
  61. - (NSString *)stringForStringListID:(SInt16)stringListID andIndex:(SInt16)index
  62. {
  63. // Get resource, and dereference the handle.
  64. Handle stringHandle = Get1Resource('STR#', stringListID);
  65. if (stringHandle == NULL) {
  66. return nil;
  67. }
  68. unsigned char *p = (unsigned char *)*stringHandle;
  69. if (!p)
  70. return nil;
  71. // Check the index against the length of the string list, then skip the length.
  72. if (index < 1 || index > *(SInt16 *)p)
  73. return nil;
  74. p += sizeof(SInt16);
  75. // Skip any strings that come before the one we are looking for.
  76. while (--index)
  77. p += 1 + *p;
  78. // Convert the one we found into an NSString.
  79. return [[[NSString alloc] initWithBytes:(p + 1) length:*p encoding:[NSString _web_encodingForResource:stringHandle]] autorelease];
  80. }
  81. - (BOOL)getPluginInfoFromResources
  82. {
  83. SInt16 resRef = [self openResourceFile];
  84. if (resRef == -1)
  85. return NO;
  86. UseResFile(resRef);
  87. if (ResError() != noErr)
  88. return NO;
  89. NSString *MIME, *extensionsList, *description;
  90. NSArray *extensions;
  91. unsigned i;
  92. for (i=1; 1; i+=2) {
  93. MIME = [[self stringForStringListID:MIMEListStringStringNumber
  94. andIndex:i] lowercaseString];
  95. if (!MIME)
  96. break;
  97. MimeClassInfo mimeClassInfo;
  98. mimeClassInfo.type = String(MIME).lower();
  99. extensionsList = [[self stringForStringListID:MIMEListStringStringNumber andIndex:i+1] lowercaseString];
  100. if (extensionsList) {
  101. extensions = [extensionsList componentsSeparatedByString:@","];
  102. for (NSUInteger j = 0; j < [extensions count]; ++j)
  103. mimeClassInfo.extensions.append((NSString *)[extensions objectAtIndex:j]);
  104. }
  105. description = [self stringForStringListID:MIMEDescriptionStringNumber
  106. andIndex:pluginInfo.mimes.size() + 1];
  107. mimeClassInfo.desc = description;
  108. pluginInfo.mimes.append(mimeClassInfo);
  109. }
  110. NSString *filename = [(NSString *)path lastPathComponent];
  111. pluginInfo.file = filename;
  112. description = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:1];
  113. if (!description)
  114. description = filename;
  115. pluginInfo.desc = description;
  116. NSString *theName = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:2];
  117. if (!theName)
  118. theName = filename;
  119. pluginInfo.name = theName;
  120. pluginInfo.isApplicationPlugin = false;
  121. [self closeResourceFile:resRef];
  122. return YES;
  123. }
  124. #if COMPILER(CLANG)
  125. #pragma clang diagnostic pop
  126. #endif
  127. - (BOOL)_initWithPath:(NSString *)pluginPath
  128. {
  129. resourceRef = -1;
  130. OSType type = 0;
  131. if (!cfBundle)
  132. return NO;
  133. CFBundleGetPackageInfo(cfBundle.get(), &type, NULL);
  134. if (type != FOUR_CHAR_CODE('BRPL'))
  135. return NO;
  136. #if USE(PLUGIN_HOST_PROCESS)
  137. RetainPtr<CFArrayRef> archs = adoptCF(CFBundleCopyExecutableArchitectures(cfBundle.get()));
  138. if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureX86_64]])
  139. pluginHostArchitecture = CPU_TYPE_X86_64;
  140. else if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureI386]])
  141. pluginHostArchitecture = CPU_TYPE_X86;
  142. else
  143. return NO;
  144. #else
  145. RetainPtr<CFURLRef> executableURL = adoptCF(CFBundleCopyExecutableURL(cfBundle.get()));
  146. if (!executableURL)
  147. return NO;
  148. NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[(NSURL *)executableURL.get() path]];
  149. NSData *data = [executableFile readDataOfLength:512];
  150. [executableFile closeFile];
  151. if (![self isNativeLibraryData:data])
  152. return NO;
  153. #endif
  154. if (![self getPluginInfoFromPLists] && ![self getPluginInfoFromResources])
  155. return NO;
  156. return YES;
  157. }
  158. - (id)initWithPath:(NSString *)pluginPath
  159. {
  160. if (!(self = [super initWithPath:pluginPath]))
  161. return nil;
  162. // Initializing a plugin package can cause it to be loaded. If there was an error initializing the plugin package,
  163. // ensure that it is unloaded before deallocating it (WebBasePluginPackage requires & asserts this).
  164. if (![self _initWithPath:pluginPath]) {
  165. [self _unloadWithShutdown:YES];
  166. [self release];
  167. return nil;
  168. }
  169. return self;
  170. }
  171. #if USE(PLUGIN_HOST_PROCESS)
  172. - (cpu_type_t)pluginHostArchitecture
  173. {
  174. return pluginHostArchitecture;
  175. }
  176. - (void)createPropertyListFile
  177. {
  178. NetscapePluginHostManager::shared().createPropertyListFile(path, pluginHostArchitecture, [self bundleIdentifier]);
  179. }
  180. #endif
  181. - (void)unload
  182. {
  183. [self _unloadWithShutdown:YES];
  184. }
  185. - (BOOL)_tryLoad
  186. {
  187. NP_GetEntryPointsFuncPtr NP_GetEntryPoints = NULL;
  188. NP_InitializeFuncPtr NP_Initialize = NULL;
  189. NPError npErr;
  190. #if !LOG_DISABLED
  191. CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
  192. CFAbsoluteTime currentTime;
  193. CFAbsoluteTime duration;
  194. #endif
  195. LOG(Plugins, "%f Load timing started for: %@", start, (NSString *)[self pluginInfo].name);
  196. if (isLoaded)
  197. return YES;
  198. if (!CFBundleLoadExecutable(cfBundle.get()))
  199. return NO;
  200. #if !LOG_DISABLED
  201. currentTime = CFAbsoluteTimeGetCurrent();
  202. duration = currentTime - start;
  203. #endif
  204. LOG(Plugins, "%f CFBundleLoadExecutable took %f seconds", currentTime, duration);
  205. isLoaded = YES;
  206. NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Initialize"));
  207. NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_GetEntryPoints"));
  208. NP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Shutdown"));
  209. if (!NP_Initialize || !NP_GetEntryPoints || !NP_Shutdown)
  210. return NO;
  211. #if COMPILER(CLANG)
  212. #pragma clang diagnostic push
  213. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  214. #endif
  215. // Plugins (at least QT) require that you call UseResFile on the resource file before loading it.
  216. resourceRef = [self openResourceFile];
  217. if (resourceRef != -1) {
  218. UseResFile(resourceRef);
  219. }
  220. #if COMPILER(CLANG)
  221. #pragma clang diagnostic pop
  222. #endif
  223. browserFuncs.version = NP_VERSION_MINOR;
  224. browserFuncs.size = sizeof(NPNetscapeFuncs);
  225. browserFuncs.geturl = NPN_GetURL;
  226. browserFuncs.posturl = NPN_PostURL;
  227. browserFuncs.requestread = NPN_RequestRead;
  228. browserFuncs.newstream = NPN_NewStream;
  229. browserFuncs.write = NPN_Write;
  230. browserFuncs.destroystream = NPN_DestroyStream;
  231. browserFuncs.status = NPN_Status;
  232. browserFuncs.uagent = NPN_UserAgent;
  233. browserFuncs.memalloc = NPN_MemAlloc;
  234. browserFuncs.memfree = NPN_MemFree;
  235. browserFuncs.memflush = NPN_MemFlush;
  236. browserFuncs.reloadplugins = NPN_ReloadPlugins;
  237. browserFuncs.geturlnotify = NPN_GetURLNotify;
  238. browserFuncs.posturlnotify = NPN_PostURLNotify;
  239. browserFuncs.getvalue = NPN_GetValue;
  240. browserFuncs.setvalue = NPN_SetValue;
  241. browserFuncs.invalidaterect = NPN_InvalidateRect;
  242. browserFuncs.invalidateregion = NPN_InvalidateRegion;
  243. browserFuncs.forceredraw = NPN_ForceRedraw;
  244. browserFuncs.getJavaEnv = NPN_GetJavaEnv;
  245. browserFuncs.getJavaPeer = NPN_GetJavaPeer;
  246. browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
  247. browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
  248. browserFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
  249. browserFuncs.getvalueforurl = NPN_GetValueForURL;
  250. browserFuncs.setvalueforurl = NPN_SetValueForURL;
  251. browserFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
  252. browserFuncs.scheduletimer = NPN_ScheduleTimer;
  253. browserFuncs.unscheduletimer = NPN_UnscheduleTimer;
  254. browserFuncs.popupcontextmenu = NPN_PopUpContextMenu;
  255. browserFuncs.convertpoint = NPN_ConvertPoint;
  256. browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue;
  257. browserFuncs.getstringidentifier = _NPN_GetStringIdentifier;
  258. browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers;
  259. browserFuncs.getintidentifier = _NPN_GetIntIdentifier;
  260. browserFuncs.identifierisstring = _NPN_IdentifierIsString;
  261. browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier;
  262. browserFuncs.intfromidentifier = _NPN_IntFromIdentifier;
  263. browserFuncs.createobject = _NPN_CreateObject;
  264. browserFuncs.retainobject = _NPN_RetainObject;
  265. browserFuncs.releaseobject = _NPN_ReleaseObject;
  266. browserFuncs.hasmethod = _NPN_HasMethod;
  267. browserFuncs.invoke = _NPN_Invoke;
  268. browserFuncs.invokeDefault = _NPN_InvokeDefault;
  269. browserFuncs.evaluate = _NPN_Evaluate;
  270. browserFuncs.hasproperty = _NPN_HasProperty;
  271. browserFuncs.getproperty = _NPN_GetProperty;
  272. browserFuncs.setproperty = _NPN_SetProperty;
  273. browserFuncs.removeproperty = _NPN_RemoveProperty;
  274. browserFuncs.setexception = _NPN_SetException;
  275. browserFuncs.enumerate = _NPN_Enumerate;
  276. browserFuncs.construct = _NPN_Construct;
  277. #if !LOG_DISABLED
  278. CFAbsoluteTime initializeStart = CFAbsoluteTimeGetCurrent();
  279. #endif
  280. LOG(Plugins, "%f NP_Initialize timing started", initializeStart);
  281. npErr = NP_Initialize(&browserFuncs);
  282. if (npErr != NPERR_NO_ERROR)
  283. return NO;
  284. #if !LOG_DISABLED
  285. currentTime = CFAbsoluteTimeGetCurrent();
  286. duration = currentTime - initializeStart;
  287. #endif
  288. LOG(Plugins, "%f NP_Initialize took %f seconds", currentTime, duration);
  289. pluginFuncs.size = sizeof(NPPluginFuncs);
  290. npErr = NP_GetEntryPoints(&pluginFuncs);
  291. if (npErr != NPERR_NO_ERROR)
  292. return NO;
  293. pluginSize = pluginFuncs.size;
  294. pluginVersion = pluginFuncs.version;
  295. if (pluginFuncs.javaClass)
  296. LOG(LiveConnect, "%@: mach-o entry point for NPP_GetJavaClass = %p", (NSString *)[self pluginInfo].name, pluginFuncs.javaClass);
  297. else
  298. LOG(LiveConnect, "%@: no entry point for NPP_GetJavaClass", (NSString *)[self pluginInfo].name);
  299. #if !LOG_DISABLED
  300. currentTime = CFAbsoluteTimeGetCurrent();
  301. duration = currentTime - start;
  302. #endif
  303. LOG(Plugins, "%f Total load time: %f seconds", currentTime, duration);
  304. return YES;
  305. }
  306. - (BOOL)load
  307. {
  308. if ([self _tryLoad])
  309. return [super load];
  310. [self _unloadWithShutdown:NO];
  311. return NO;
  312. }
  313. - (NPPluginFuncs *)pluginFuncs
  314. {
  315. return &pluginFuncs;
  316. }
  317. - (NPNetscapeFuncs *)browserFuncs
  318. {
  319. return &browserFuncs;
  320. }
  321. - (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
  322. {
  323. [super wasRemovedFromPluginDatabase:database];
  324. // Unload when removed from final plug-in database
  325. if ([pluginDatabases count] == 0)
  326. [self _unloadWithShutdown:YES];
  327. }
  328. - (void)open
  329. {
  330. instanceCount++;
  331. // Handle the case where all instances close a plug-in package, but another
  332. // instance opens the package before it is unloaded (which only happens when
  333. // the plug-in database is refreshed)
  334. needsUnload = NO;
  335. if (!isLoaded) {
  336. // Should load when the first instance opens the plug-in package
  337. ASSERT(instanceCount == 1);
  338. [self load];
  339. }
  340. }
  341. - (void)close
  342. {
  343. ASSERT(instanceCount > 0);
  344. instanceCount--;
  345. if (instanceCount == 0 && needsUnload)
  346. [self _unloadWithShutdown:YES];
  347. }
  348. - (BOOL)supportsSnapshotting
  349. {
  350. if ([self bundleIdentifier] != "com.macromedia.Flash Player.plugin")
  351. return YES;
  352. // Flash has a bogus Info.plist entry for CFBundleVersionString, so use CFBundleShortVersionString.
  353. NSString *versionString = (NSString *)CFDictionaryGetValue(CFBundleGetInfoDictionary(cfBundle.get()), CFSTR("CFBundleShortVersionString"));
  354. if (![versionString hasPrefix:@"10.1"])
  355. return YES;
  356. // Some prerelease versions of Flash 10.1 crash when sent a drawRect event using the CA drawing model: <rdar://problem/7739922>
  357. return CFStringCompare((CFStringRef)versionString, CFSTR("10.1.53.60"), kCFCompareNumerically) != kCFCompareLessThan;
  358. }
  359. @end
  360. @implementation WebNetscapePluginPackage (Internal)
  361. - (void)_unloadWithShutdown:(BOOL)shutdown
  362. {
  363. if (!isLoaded)
  364. return;
  365. LOG(Plugins, "Unloading %@...", (NSString *)pluginInfo.name);
  366. // Cannot unload a plug-in package while an instance is still using it
  367. if (instanceCount > 0) {
  368. needsUnload = YES;
  369. return;
  370. }
  371. if (shutdown && NP_Shutdown)
  372. NP_Shutdown();
  373. if (resourceRef != -1)
  374. [self closeResourceFile:resourceRef];
  375. LOG(Plugins, "Plugin Unloaded");
  376. isLoaded = NO;
  377. }
  378. @end
  379. #endif