blob: a50a35bcb1596b85ab7ca06c562110a32fca3cd0 [file] [log] [blame]
/*
* 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 Computer, 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.
*/
#ifndef __LP64__
#import "WebNetscapePluginPackage.h"
#import "WebKitLogging.h"
#import "WebKitNSStringExtras.h"
#import "WebNSObjectExtras.h"
#import "WebNetscapeDeprecatedFunctions.h"
#import <JavaScriptCore/npruntime_impl.h>
#ifdef SUPPORT_CFM
typedef void (* FunctionPointer)(void);
typedef void (* TransitionVector)(void);
static FunctionPointer functionPointerForTVector(TransitionVector);
static TransitionVector tVectorForFunctionPointer(FunctionPointer);
#endif
#define PluginNameOrDescriptionStringNumber 126
#define MIMEDescriptionStringNumber 127
#define MIMEListStringStringNumber 128
#define RealPlayerAppIndentifier @"com.RealNetworks.RealOne Player"
#define RealPlayerPluginFilename @"RealPlayer Plugin"
@interface WebNetscapePluginPackage (Internal)
- (void)_unloadWithShutdown:(BOOL)shutdown;
@end
@implementation WebNetscapePluginPackage
#ifndef __LP64__
+ (void)initialize
{
// The Shockwave plugin requires a valid file in CurApRefNum.
// But it doesn't seem to matter what file it is.
// If we're called inside a Cocoa application which won't have a
// CurApRefNum, we set it to point to the system resource file.
// Call CurResFile before testing the result of WebLMGetCurApRefNum.
// If we are called before the bundle resource map has been opened
// for a Carbon application (or a Cocoa app with Resource Manager
// resources) we *do not* want to set CurApRefNum to point at the
// system resource file. CurResFile triggers Resource Manager lazy
// initialization, and will open the bundle resource map as necessary.
CurResFile();
if (WebLMGetCurApRefNum() == -1) {
// To get the refNum for the system resource file, we have to do
// UseResFile(kSystemResFile) and then look at CurResFile().
short savedCurResFile = CurResFile();
UseResFile(kSystemResFile);
WebLMSetCurApRefNum(CurResFile());
UseResFile(savedCurResFile);
}
}
#endif
- (ResFileRefNum)openResourceFile
{
#ifdef SUPPORT_CFM
if (!isBundle) {
FSRef fref;
OSErr err = FSPathMakeRef((const UInt8 *)[path fileSystemRepresentation], &fref, NULL);
if (err != noErr)
return -1;
return FSOpenResFile(&fref, fsRdPerm);
}
#endif
return CFBundleOpenBundleResourceMap(cfBundle);
}
- (void)closeResourceFile:(ResFileRefNum)resRef
{
#ifdef SUPPORT_CFM
if (!isBundle) {
CloseResFile(resRef);
return;
}
#endif
CFBundleCloseBundleResourceMap(cfBundle, resRef);
}
- (NSString *)stringForStringListID:(SInt16)stringListID andIndex:(SInt16)index
{
// Get resource, and dereference the handle.
Handle stringHandle = Get1Resource('STR#', stringListID);
if (stringHandle == NULL) {
return nil;
}
unsigned char *p = (unsigned char *)*stringHandle;
if (!p)
return nil;
// Check the index against the length of the string list, then skip the length.
if (index < 1 || index > *(SInt16 *)p)
return nil;
p += sizeof(SInt16);
// Skip any strings that come before the one we are looking for.
while (--index)
p += 1 + *p;
// Convert the one we found into an NSString.
return [[[NSString alloc] initWithBytes:(p + 1) length:*p encoding:[NSString _web_encodingForResource:stringHandle]] autorelease];
}
- (BOOL)getPluginInfoFromResources
{
SInt16 resRef = [self openResourceFile];
if (resRef == -1)
return NO;
UseResFile(resRef);
if (ResError() != noErr)
return NO;
NSString *MIME, *extensionsList, *description;
NSArray *extensions;
unsigned i;
NSMutableDictionary *MIMEToExtensionsDictionary = [NSMutableDictionary dictionary];
NSMutableDictionary *MIMEToDescriptionDictionary = [NSMutableDictionary dictionary];
for (i=1; 1; i+=2) {
MIME = [[self stringForStringListID:MIMEListStringStringNumber
andIndex:i] lowercaseString];
if (!MIME)
break;
extensionsList = [[self stringForStringListID:MIMEListStringStringNumber andIndex:i+1] lowercaseString];
if (extensionsList) {
extensions = [extensionsList componentsSeparatedByString:@","];
[MIMEToExtensionsDictionary setObject:extensions forKey:MIME];
} else
// DRM and WMP claim MIMEs without extensions. Use a @"" extension in this case.
[MIMEToExtensionsDictionary setObject:[NSArray arrayWithObject:@""] forKey:MIME];
description = [self stringForStringListID:MIMEDescriptionStringNumber
andIndex:[MIMEToExtensionsDictionary count]];
if (description)
[MIMEToDescriptionDictionary setObject:description forKey:MIME];
else
[MIMEToDescriptionDictionary setObject:@"" forKey:MIME];
}
[self setMIMEToDescriptionDictionary:MIMEToDescriptionDictionary];
[self setMIMEToExtensionsDictionary:MIMEToExtensionsDictionary];
NSString *filename = [self filename];
description = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:1];
if (!description)
description = filename;
[self setPluginDescription:description];
NSString *theName = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:2];
if (!theName)
theName = filename;
[self setName:theName];
[self closeResourceFile:resRef];
return YES;
}
- (BOOL)_initWithPath:(NSString *)pluginPath
{
resourceRef = -1;
OSType type = 0;
if (bundle) {
// Bundle
CFBundleGetPackageInfo(cfBundle, &type, NULL);
#ifdef SUPPORT_CFM
isBundle = YES;
#endif
} else {
#ifdef SUPPORT_CFM
// Single-file plug-in with resource fork
type = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] fileHFSTypeCode];
isBundle = NO;
isCFM = YES;
#else
return NO;
#endif
}
if (type != FOUR_CHAR_CODE('BRPL'))
return NO;
// Check if the executable is Mach-O or CFM.
if (bundle) {
NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[bundle executablePath]];
NSData *data = [executableFile readDataOfLength:512];
[executableFile closeFile];
// Check the length of the data before calling memcmp. We think this fixes 3782543.
if (data == nil || [data length] < 8)
return NO;
BOOL hasCFMHeader = memcmp([data bytes], "Joy!peff", 8) == 0;
#ifdef SUPPORT_CFM
isCFM = hasCFMHeader;
#else
if (hasCFMHeader)
return NO;
#endif
if (![self isNativeLibraryData:data])
return NO;
}
if (![self getPluginInfoFromPLists] && ![self getPluginInfoFromResources])
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;
}
- (WebExecutableType)executableType
{
#ifdef SUPPORT_CFM
if (isCFM)
return WebCFMExecutableType;
#endif
return WebMachOExecutableType;
}
- (void)launchRealPlayer
{
CFURLRef appURL = NULL;
OSStatus error = LSFindApplicationForInfo(kLSUnknownCreator, (CFStringRef)RealPlayerAppIndentifier, NULL, NULL, &appURL);
if (!error) {
LSLaunchURLSpec URLSpec;
bzero(&URLSpec, sizeof(URLSpec));
URLSpec.launchFlags = kLSLaunchDefaults | kLSLaunchDontSwitch;
URLSpec.appURL = appURL;
LSOpenFromURLSpec(&URLSpec, NULL);
CFRelease(appURL);
}
}
- (void)_applyDjVuWorkaround
{
if (!cfBundle)
return;
if ([(NSString *)CFBundleGetIdentifier(cfBundle) isEqualToString:@"com.lizardtech.NPDjVu"]) {
// The DjVu plug-in will crash copying the vtable if it's too big so we cap it to
// what the plug-in expects here.
// size + version + 40 function pointers.
browserFuncs.size = 2 + 2 + sizeof(void *) * 40;
}
}
- (void)unload
{
[self _unloadWithShutdown:YES];
}
- (BOOL)load
{
NP_GetEntryPointsFuncPtr NP_GetEntryPoints = NULL;
NP_InitializeFuncPtr NP_Initialize = NULL;
NPError npErr;
#ifdef SUPPORT_CFM
MainFuncPtr pluginMainFunc = NULL;
#endif
#if !LOG_DISABLED
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime currentTime;
CFAbsoluteTime duration;
#endif
LOG(Plugins, "%f Load timing started for: %@", start, [self name]);
if (isLoaded)
return YES;
#ifdef SUPPORT_CFM
if (isBundle) {
#endif
if (!CFBundleLoadExecutable(cfBundle))
goto abort;
#if !LOG_DISABLED
currentTime = CFAbsoluteTimeGetCurrent();
duration = currentTime - start;
#endif
LOG(Plugins, "%f CFBundleLoadExecutable took %f seconds", currentTime, duration);
isLoaded = YES;
#ifdef SUPPORT_CFM
if (isCFM) {
pluginMainFunc = (MainFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("main") );
if (!pluginMainFunc)
goto abort;
} else {
#endif
NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Initialize"));
NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_GetEntryPoints"));
NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Shutdown"));
if (!NP_Initialize || !NP_GetEntryPoints || !NPP_Shutdown)
goto abort;
#ifdef SUPPORT_CFM
}
} else {
// single CFM file
FSSpec spec;
FSRef fref;
OSErr err;
err = FSPathMakeRef((UInt8 *)[path fileSystemRepresentation], &fref, NULL);
if (err != noErr) {
LOG_ERROR("FSPathMakeRef failed. Error=%d", err);
goto abort;
}
err = FSGetCatalogInfo(&fref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
if (err != noErr) {
LOG_ERROR("FSGetCatalogInfo failed. Error=%d", err);
goto abort;
}
err = WebGetDiskFragment(&spec, 0, kCFragGoesToEOF, nil, kPrivateCFragCopy, &connID, (Ptr *)&pluginMainFunc, nil);
if (err != noErr) {
LOG_ERROR("WebGetDiskFragment failed. Error=%d", err);
goto abort;
}
#if !LOG_DISABLED
currentTime = CFAbsoluteTimeGetCurrent();
duration = currentTime - start;
#endif
LOG(Plugins, "%f WebGetDiskFragment took %f seconds", currentTime, duration);
isLoaded = YES;
pluginMainFunc = (MainFuncPtr)functionPointerForTVector((TransitionVector)pluginMainFunc);
if (!pluginMainFunc) {
goto abort;
}
// NOTE: pluginMainFunc is freed after it is called. Be sure not to return before that.
isCFM = YES;
}
#endif /* SUPPORT_CFM */
// Plugins (at least QT) require that you call UseResFile on the resource file before loading it.
resourceRef = [self openResourceFile];
if (resourceRef != -1) {
UseResFile(resourceRef);
}
// swap function tables
#ifdef SUPPORT_CFM
if (isCFM) {
browserFuncs.version = NP_VERSION_MINOR;
browserFuncs.size = sizeof(NPNetscapeFuncs);
browserFuncs.geturl = (NPN_GetURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURL);
browserFuncs.posturl = (NPN_PostURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURL);
browserFuncs.requestread = (NPN_RequestReadProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_RequestRead);
browserFuncs.newstream = (NPN_NewStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_NewStream);
browserFuncs.write = (NPN_WriteProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Write);
browserFuncs.destroystream = (NPN_DestroyStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_DestroyStream);
browserFuncs.status = (NPN_StatusProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Status);
browserFuncs.uagent = (NPN_UserAgentProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_UserAgent);
browserFuncs.memalloc = (NPN_MemAllocProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemAlloc);
browserFuncs.memfree = (NPN_MemFreeProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFree);
browserFuncs.memflush = (NPN_MemFlushProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFlush);
browserFuncs.reloadplugins = (NPN_ReloadPluginsProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ReloadPlugins);
browserFuncs.geturlnotify = (NPN_GetURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURLNotify);
browserFuncs.posturlnotify = (NPN_PostURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURLNotify);
browserFuncs.getvalue = (NPN_GetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetValue);
browserFuncs.setvalue = (NPN_SetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_SetValue);
browserFuncs.invalidaterect = (NPN_InvalidateRectProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRect);
browserFuncs.invalidateregion = (NPN_InvalidateRegionProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRegion);
browserFuncs.forceredraw = (NPN_ForceRedrawProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ForceRedraw);
browserFuncs.getJavaEnv = (NPN_GetJavaEnvProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaEnv);
browserFuncs.getJavaPeer = (NPN_GetJavaPeerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaPeer);
browserFuncs.pushpopupsenabledstate = (NPN_PushPopupsEnabledStateProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PushPopupsEnabledState);
browserFuncs.poppopupsenabledstate = (NPN_PopPopupsEnabledStateProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PopPopupsEnabledState);
browserFuncs.releasevariantvalue = (NPN_ReleaseVariantValueProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseVariantValue);
browserFuncs.getstringidentifier = (NPN_GetStringIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifier);
browserFuncs.getstringidentifiers = (NPN_GetStringIdentifiersProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifiers);
browserFuncs.getintidentifier = (NPN_GetIntIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetIntIdentifier);
browserFuncs.identifierisstring = (NPN_IdentifierIsStringProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_IdentifierIsString);
browserFuncs.utf8fromidentifier = (NPN_UTF8FromIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_UTF8FromIdentifier);
browserFuncs.createobject = (NPN_CreateObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_CreateObject);
browserFuncs.retainobject = (NPN_RetainObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RetainObject);
browserFuncs.releaseobject = (NPN_ReleaseObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseObject);
browserFuncs.invoke = (NPN_InvokeProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Invoke);
browserFuncs.invokeDefault = (NPN_InvokeDefaultProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_InvokeDefault);
browserFuncs.evaluate = (NPN_EvaluateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Evaluate);
browserFuncs.getproperty = (NPN_GetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetProperty);
browserFuncs.setproperty = (NPN_SetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetProperty);
browserFuncs.removeproperty = (NPN_RemovePropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RemoveProperty);
browserFuncs.setexception = (NPN_SetExceptionProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetException);
browserFuncs.enumerate = (NPN_EnumerateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Enumerate);
[self _applyDjVuWorkaround];
#if !LOG_DISABLED
CFAbsoluteTime mainStart = CFAbsoluteTimeGetCurrent();
#endif
LOG(Plugins, "%f main timing started", mainStart);
NPP_ShutdownProcPtr shutdownFunction;
npErr = pluginMainFunc(&browserFuncs, &pluginFuncs, &shutdownFunction);
NPP_Shutdown = (NPP_ShutdownProcPtr)functionPointerForTVector((TransitionVector)shutdownFunction);
if (!isBundle)
// Don't free pluginMainFunc if we got it from a bundle because it is owned by CFBundle in that case.
free(pluginMainFunc);
// Workaround for 3270576. The RealPlayer plug-in fails to load if its preference file is out of date.
// Launch the RealPlayer application to refresh the file.
if (npErr != NPERR_NO_ERROR) {
if (npErr == NPERR_MODULE_LOAD_FAILED_ERROR && [[self filename] isEqualToString:RealPlayerPluginFilename])
[self launchRealPlayer];
goto abort;
}
#if !LOG_DISABLED
currentTime = CFAbsoluteTimeGetCurrent();
duration = currentTime - mainStart;
#endif
LOG(Plugins, "%f main took %f seconds", currentTime, duration);
pluginSize = pluginFuncs.size;
pluginVersion = pluginFuncs.version;
LOG(Plugins, "pluginMainFunc: %d, size=%d, version=%d", npErr, pluginSize, pluginVersion);
NPP_New = (NPP_NewProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newp);
NPP_Destroy = (NPP_DestroyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroy);
NPP_SetWindow = (NPP_SetWindowProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setwindow);
NPP_NewStream = (NPP_NewStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newstream);
NPP_DestroyStream = (NPP_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroystream);
NPP_StreamAsFile = (NPP_StreamAsFileProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.asfile);
NPP_WriteReady = (NPP_WriteReadyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.writeready);
NPP_Write = (NPP_WriteProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.write);
NPP_Print = (NPP_PrintProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.print);
NPP_HandleEvent = (NPP_HandleEventProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.event);
NPP_URLNotify = (NPP_URLNotifyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.urlnotify);
NPP_GetValue = (NPP_GetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.getvalue);
NPP_SetValue = (NPP_SetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setvalue);
// LiveConnect support
NPP_GetJavaClass = (NPP_GetJavaClassProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.javaClass);
if (NPP_GetJavaClass) {
LOG(LiveConnect, "%@: CFM entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass);
} else {
LOG(LiveConnect, "%@: no entry point for NPP_GetJavaClass", [self name]);
}
} else {
#endif
// no function pointer conversion necessary for Mach-O
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.releasevariantvalue = _NPN_ReleaseVariantValue;
browserFuncs.getstringidentifier = _NPN_GetStringIdentifier;
browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers;
browserFuncs.getintidentifier = _NPN_GetIntIdentifier;
browserFuncs.identifierisstring = _NPN_IdentifierIsString;
browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier;
browserFuncs.createobject = _NPN_CreateObject;
browserFuncs.retainobject = _NPN_RetainObject;
browserFuncs.releaseobject = _NPN_ReleaseObject;
browserFuncs.invoke = _NPN_Invoke;
browserFuncs.invokeDefault = _NPN_InvokeDefault;
browserFuncs.evaluate = _NPN_Evaluate;
browserFuncs.getproperty = _NPN_GetProperty;
browserFuncs.setproperty = _NPN_SetProperty;
browserFuncs.removeproperty = _NPN_RemoveProperty;
browserFuncs.setexception = _NPN_SetException;
browserFuncs.enumerate = _NPN_Enumerate;
[self _applyDjVuWorkaround];
#if !LOG_DISABLED
CFAbsoluteTime initializeStart = CFAbsoluteTimeGetCurrent();
#endif
LOG(Plugins, "%f NP_Initialize timing started", initializeStart);
npErr = NP_Initialize(&browserFuncs);
if (npErr != NPERR_NO_ERROR)
goto abort;
#if !LOG_DISABLED
currentTime = CFAbsoluteTimeGetCurrent();
duration = currentTime - initializeStart;
#endif
LOG(Plugins, "%f NP_Initialize took %f seconds", currentTime, duration);
npErr = NP_GetEntryPoints(&pluginFuncs);
if (npErr != NPERR_NO_ERROR)
goto abort;
pluginSize = pluginFuncs.size;
pluginVersion = pluginFuncs.version;
NPP_New = pluginFuncs.newp;
NPP_Destroy = pluginFuncs.destroy;
NPP_SetWindow = pluginFuncs.setwindow;
NPP_NewStream = pluginFuncs.newstream;
NPP_DestroyStream = pluginFuncs.destroystream;
NPP_StreamAsFile = pluginFuncs.asfile;
NPP_WriteReady = pluginFuncs.writeready;
NPP_Write = pluginFuncs.write;
NPP_Print = pluginFuncs.print;
NPP_HandleEvent = pluginFuncs.event;
NPP_URLNotify = pluginFuncs.urlnotify;
NPP_GetValue = pluginFuncs.getvalue;
NPP_SetValue = pluginFuncs.setvalue;
// LiveConnect support
NPP_GetJavaClass = pluginFuncs.javaClass;
if (NPP_GetJavaClass){
LOG(LiveConnect, "%@: mach-o entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass);
} else {
LOG(LiveConnect, "%@: no entry point for NPP_GetJavaClass", [self name]);
}
#ifdef SUPPORT_CFM
}
#endif
#if !LOG_DISABLED
currentTime = CFAbsoluteTimeGetCurrent();
duration = currentTime - start;
#endif
LOG(Plugins, "%f Total load time: %f seconds", currentTime, duration);
return [super load];
abort:
[self _unloadWithShutdown:NO];
return NO;
}
- (NPP_SetWindowProcPtr)NPP_SetWindow
{
return NPP_SetWindow;
}
- (NPP_NewProcPtr)NPP_New
{
return NPP_New;
}
- (NPP_DestroyProcPtr)NPP_Destroy
{
return NPP_Destroy;
}
- (NPP_NewStreamProcPtr)NPP_NewStream
{
return NPP_NewStream;
}
- (NPP_StreamAsFileProcPtr)NPP_StreamAsFile
{
return NPP_StreamAsFile;
}
- (NPP_DestroyStreamProcPtr)NPP_DestroyStream
{
return NPP_DestroyStream;
}
- (NPP_WriteReadyProcPtr)NPP_WriteReady
{
return NPP_WriteReady;
}
- (NPP_WriteProcPtr)NPP_Write
{
return NPP_Write;
}
- (NPP_HandleEventProcPtr)NPP_HandleEvent
{
return NPP_HandleEvent;
}
-(NPP_URLNotifyProcPtr)NPP_URLNotify
{
return NPP_URLNotify;
}
-(NPP_GetValueProcPtr)NPP_GetValue
{
return NPP_GetValue;
}
-(NPP_SetValueProcPtr)NPP_SetValue
{
return NPP_SetValue;
}
-(NPP_PrintProcPtr)NPP_Print
{
return NPP_Print;
}
- (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];
}
@end
#ifdef SUPPORT_CFM
// function pointer converters
FunctionPointer functionPointerForTVector(TransitionVector tvp)
{
const uint32 temp[6] = {0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420};
uint32 *newGlue = NULL;
if (tvp != NULL) {
newGlue = (uint32 *)malloc(sizeof(temp));
if (newGlue != NULL) {
unsigned i;
for (i = 0; i < 6; i++) newGlue[i] = temp[i];
newGlue[0] |= ((uintptr_t)tvp >> 16);
newGlue[1] |= ((uintptr_t)tvp & 0xFFFF);
MakeDataExecutable(newGlue, sizeof(temp));
}
}
return (FunctionPointer)newGlue;
}
TransitionVector tVectorForFunctionPointer(FunctionPointer fp)
{
FunctionPointer *newGlue = NULL;
if (fp != NULL) {
newGlue = (FunctionPointer *)malloc(2 * sizeof(FunctionPointer));
if (newGlue != NULL) {
newGlue[0] = fp;
newGlue[1] = NULL;
}
}
return (TransitionVector)newGlue;
}
#endif
@implementation WebNetscapePluginPackage (Internal)
- (void)_unloadWithShutdown:(BOOL)shutdown
{
if (!isLoaded)
return;
LOG(Plugins, "Unloading %@...", name);
// Cannot unload a plug-in package while an instance is still using it
if (instanceCount > 0) {
needsUnload = YES;
return;
}
if (shutdown && NPP_Shutdown)
NPP_Shutdown();
if (resourceRef != -1)
[self closeResourceFile:resourceRef];
#ifdef SUPPORT_CFM
if (isBundle)
#endif
CFBundleUnloadExecutable(cfBundle);
#ifdef SUPPORT_CFM
else
WebCloseConnection(&connID);
#endif
LOG(Plugins, "Plugin Unloaded");
isLoaded = NO;
}
@end
#endif