| /* |
| * Copyright (C) 2005, 2006, 2007 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. |
| */ |
| |
| #if ENABLE(NETSCAPE_PLUGIN_API) |
| #import "WebNetscapePluginPackage.h" |
| |
| #import "WebKitLogging.h" |
| #import "WebKitNSStringExtras.h" |
| #import "WebNSFileManagerExtras.h" |
| #import "WebNSObjectExtras.h" |
| #import <WebCore/npruntime_impl.h> |
| #import <wtf/RetainPtr.h> |
| |
| #if USE(PLUGIN_HOST_PROCESS) |
| #import "NetscapePluginHostManager.h" |
| |
| using namespace WebKit; |
| #endif |
| |
| using namespace WebCore; |
| |
| @interface WebNetscapePluginPackage (Internal) |
| - (void)_unloadWithShutdown:(BOOL)shutdown; |
| @end |
| |
| @implementation WebNetscapePluginPackage |
| |
| - (ResFileRefNum)openResourceFile |
| { |
| ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
| return CFBundleOpenBundleResourceMap(cfBundle.get()); |
| ALLOW_DEPRECATED_DECLARATIONS_END |
| } |
| |
| - (void)closeResourceFile:(ResFileRefNum)resRef |
| { |
| ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
| CFBundleCloseBundleResourceMap(cfBundle.get(), resRef); |
| ALLOW_DEPRECATED_DECLARATIONS_END |
| } |
| |
| - (BOOL)_initWithPath:(NSString *)pluginPath |
| { |
| resourceRef = -1; |
| |
| OSType type = 0; |
| |
| if (!cfBundle) |
| return NO; |
| |
| CFBundleGetPackageInfo(cfBundle.get(), &type, NULL); |
| |
| if (type != FOUR_CHAR_CODE('BRPL')) |
| return NO; |
| |
| #if USE(PLUGIN_HOST_PROCESS) |
| auto archs = adoptCF(CFBundleCopyExecutableArchitectures(cfBundle.get())); |
| if ([(__bridge NSArray *)archs.get() containsObject:@(NSBundleExecutableArchitectureX86_64)]) |
| pluginHostArchitecture = CPU_TYPE_X86_64; |
| else if ([(__bridge NSArray *)archs.get() containsObject:@(NSBundleExecutableArchitectureI386)]) |
| pluginHostArchitecture = CPU_TYPE_X86; |
| else |
| return NO; |
| #else |
| RetainPtr<CFURLRef> executableURL = adoptCF(CFBundleCopyExecutableURL(cfBundle.get())); |
| if (!executableURL) |
| return NO; |
| NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[(NSURL *)executableURL.get() path]]; |
| NSData *data = [executableFile readDataOfLength:512]; |
| [executableFile closeFile]; |
| |
| if (![self isNativeLibraryData:data]) |
| return NO; |
| #endif |
| |
| if (![self getPluginInfoFromPLists]) |
| return NO; |
| |
| return YES; |
| } |
| |
| - (id)initWithPath:(NSString *)pluginPath |
| { |
| if (!(self = [super initWithPath:pluginPath])) |
| return nil; |
| |
| // Initializing a plugin package can cause it to be loaded. If there was an error initializing the plugin package, |
| // ensure that it is unloaded before deallocating it (WebBasePluginPackage requires & asserts this). |
| if (![self _initWithPath:pluginPath]) { |
| [self _unloadWithShutdown:YES]; |
| [self release]; |
| return nil; |
| } |
| |
| return self; |
| } |
| |
| #if USE(PLUGIN_HOST_PROCESS) |
| |
| - (cpu_type_t)pluginHostArchitecture |
| { |
| return pluginHostArchitecture; |
| } |
| |
| - (void)createPropertyListFile |
| { |
| NetscapePluginHostManager::singleton().createPropertyListFile(path, pluginHostArchitecture, [self bundleIdentifier]); |
| } |
| |
| #endif |
| |
| - (void)unload |
| { |
| [self _unloadWithShutdown:YES]; |
| } |
| |
| - (BOOL)_tryLoad |
| { |
| NP_GetEntryPointsFuncPtr NP_GetEntryPoints = NULL; |
| NP_InitializeFuncPtr NP_Initialize = NULL; |
| NPError npErr; |
| |
| #if !LOG_DISABLED |
| CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); |
| CFAbsoluteTime currentTime; |
| CFAbsoluteTime duration; |
| #endif |
| LOG(Plugins, "%f Load timing started for: %@", start, (NSString *)[self pluginInfo].name); |
| |
| if (isLoaded) |
| return YES; |
| |
| if (!CFBundleLoadExecutable(cfBundle.get())) |
| return NO; |
| #if !LOG_DISABLED |
| currentTime = CFAbsoluteTimeGetCurrent(); |
| duration = currentTime - start; |
| #endif |
| LOG(Plugins, "%f CFBundleLoadExecutable took %f seconds", currentTime, duration); |
| isLoaded = YES; |
| |
| NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Initialize")); |
| NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_GetEntryPoints")); |
| NP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Shutdown")); |
| if (!NP_Initialize || !NP_GetEntryPoints || !NP_Shutdown) |
| return NO; |
| |
| ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
| // Plugins (at least QT) require that you call UseResFile on the resource file before loading it. |
| resourceRef = [self openResourceFile]; |
| if (resourceRef != -1) { |
| UseResFile(resourceRef); |
| } |
| ALLOW_DEPRECATED_DECLARATIONS_END |
| |
| browserFuncs.version = NP_VERSION_MINOR; |
| browserFuncs.size = sizeof(NPNetscapeFuncs); |
| browserFuncs.geturl = NPN_GetURL; |
| browserFuncs.posturl = NPN_PostURL; |
| browserFuncs.requestread = NPN_RequestRead; |
| browserFuncs.newstream = NPN_NewStream; |
| browserFuncs.write = NPN_Write; |
| browserFuncs.destroystream = NPN_DestroyStream; |
| browserFuncs.status = NPN_Status; |
| browserFuncs.uagent = NPN_UserAgent; |
| browserFuncs.memalloc = NPN_MemAlloc; |
| browserFuncs.memfree = NPN_MemFree; |
| browserFuncs.memflush = NPN_MemFlush; |
| browserFuncs.reloadplugins = NPN_ReloadPlugins; |
| browserFuncs.geturlnotify = NPN_GetURLNotify; |
| browserFuncs.posturlnotify = NPN_PostURLNotify; |
| browserFuncs.getvalue = NPN_GetValue; |
| browserFuncs.setvalue = NPN_SetValue; |
| browserFuncs.invalidaterect = NPN_InvalidateRect; |
| browserFuncs.invalidateregion = NPN_InvalidateRegion; |
| browserFuncs.forceredraw = NPN_ForceRedraw; |
| browserFuncs.getJavaEnv = NPN_GetJavaEnv; |
| browserFuncs.getJavaPeer = NPN_GetJavaPeer; |
| browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState; |
| browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState; |
| browserFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall; |
| browserFuncs.getvalueforurl = NPN_GetValueForURL; |
| browserFuncs.setvalueforurl = NPN_SetValueForURL; |
| browserFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo; |
| browserFuncs.scheduletimer = NPN_ScheduleTimer; |
| browserFuncs.unscheduletimer = NPN_UnscheduleTimer; |
| browserFuncs.popupcontextmenu = NPN_PopUpContextMenu; |
| browserFuncs.convertpoint = NPN_ConvertPoint; |
| |
| browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue; |
| browserFuncs.getstringidentifier = _NPN_GetStringIdentifier; |
| browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers; |
| browserFuncs.getintidentifier = _NPN_GetIntIdentifier; |
| browserFuncs.identifierisstring = _NPN_IdentifierIsString; |
| browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier; |
| browserFuncs.intfromidentifier = _NPN_IntFromIdentifier; |
| browserFuncs.createobject = _NPN_CreateObject; |
| browserFuncs.retainobject = _NPN_RetainObject; |
| browserFuncs.releaseobject = _NPN_ReleaseObject; |
| browserFuncs.hasmethod = _NPN_HasMethod; |
| browserFuncs.invoke = _NPN_Invoke; |
| browserFuncs.invokeDefault = _NPN_InvokeDefault; |
| browserFuncs.evaluate = _NPN_Evaluate; |
| browserFuncs.hasproperty = _NPN_HasProperty; |
| browserFuncs.getproperty = _NPN_GetProperty; |
| browserFuncs.setproperty = _NPN_SetProperty; |
| browserFuncs.removeproperty = _NPN_RemoveProperty; |
| browserFuncs.setexception = _NPN_SetException; |
| browserFuncs.enumerate = _NPN_Enumerate; |
| browserFuncs.construct = _NPN_Construct; |
| |
| #if !LOG_DISABLED |
| CFAbsoluteTime initializeStart = CFAbsoluteTimeGetCurrent(); |
| #endif |
| LOG(Plugins, "%f NP_Initialize timing started", initializeStart); |
| npErr = NP_Initialize(&browserFuncs); |
| if (npErr != NPERR_NO_ERROR) |
| return NO; |
| #if !LOG_DISABLED |
| currentTime = CFAbsoluteTimeGetCurrent(); |
| duration = currentTime - initializeStart; |
| #endif |
| LOG(Plugins, "%f NP_Initialize took %f seconds", currentTime, duration); |
| |
| pluginFuncs.size = sizeof(NPPluginFuncs); |
| |
| npErr = NP_GetEntryPoints(&pluginFuncs); |
| if (npErr != NPERR_NO_ERROR) |
| return NO; |
| |
| pluginSize = pluginFuncs.size; |
| pluginVersion = pluginFuncs.version; |
| |
| #if !LOG_DISABLED |
| currentTime = CFAbsoluteTimeGetCurrent(); |
| duration = currentTime - start; |
| #endif |
| LOG(Plugins, "%f Total load time: %f seconds", currentTime, duration); |
| |
| return YES; |
| } |
| |
| - (BOOL)load |
| { |
| if ([self _tryLoad]) |
| return [super load]; |
| |
| [self _unloadWithShutdown:NO]; |
| return NO; |
| } |
| |
| - (NPPluginFuncs *)pluginFuncs |
| { |
| return &pluginFuncs; |
| } |
| |
| - (NPNetscapeFuncs *)browserFuncs |
| { |
| return &browserFuncs; |
| } |
| |
| - (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database |
| { |
| [super wasRemovedFromPluginDatabase:database]; |
| |
| // Unload when removed from final plug-in database |
| if ([pluginDatabases count] == 0) |
| [self _unloadWithShutdown:YES]; |
| } |
| |
| - (void)open |
| { |
| instanceCount++; |
| |
| // Handle the case where all instances close a plug-in package, but another |
| // instance opens the package before it is unloaded (which only happens when |
| // the plug-in database is refreshed) |
| needsUnload = NO; |
| |
| if (!isLoaded) { |
| // Should load when the first instance opens the plug-in package |
| ASSERT(instanceCount == 1); |
| [self load]; |
| } |
| } |
| |
| - (void)close |
| { |
| ASSERT(instanceCount > 0); |
| instanceCount--; |
| if (instanceCount == 0 && needsUnload) |
| [self _unloadWithShutdown:YES]; |
| } |
| |
| |
| - (BOOL)supportsSnapshotting |
| { |
| if ([self bundleIdentifier] != "com.macromedia.Flash Player.plugin") |
| return YES; |
| |
| // Flash has a bogus Info.plist entry for CFBundleVersionString, so use CFBundleShortVersionString. |
| NSString *versionString = (NSString *)CFDictionaryGetValue(CFBundleGetInfoDictionary(cfBundle.get()), CFSTR("CFBundleShortVersionString")); |
| |
| if (![versionString hasPrefix:@"10.1"]) |
| return YES; |
| |
| // Some prerelease versions of Flash 10.1 crash when sent a drawRect event using the CA drawing model: <rdar://problem/7739922> |
| return CFStringCompare((CFStringRef)versionString, CFSTR("10.1.53.60"), kCFCompareNumerically) != kCFCompareLessThan; |
| } |
| |
| @end |
| |
| @implementation WebNetscapePluginPackage (Internal) |
| |
| - (void)_unloadWithShutdown:(BOOL)shutdown |
| { |
| if (!isLoaded) |
| return; |
| |
| LOG(Plugins, "Unloading %@...", (NSString *)pluginInfo.name); |
| |
| // Cannot unload a plug-in package while an instance is still using it |
| if (instanceCount > 0) { |
| needsUnload = YES; |
| return; |
| } |
| |
| if (shutdown && NP_Shutdown) |
| NP_Shutdown(); |
| |
| if (resourceRef != -1) |
| [self closeResourceFile:resourceRef]; |
| |
| LOG(Plugins, "Plugin Unloaded"); |
| isLoaded = NO; |
| } |
| |
| @end |
| #endif |