WebKit/mac/Plugins/WebNetscapePluginPackage.mm
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKit/mac/Plugins/WebNetscapePluginPackage.mm	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,782 @@
+/*
+ * 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.
+ */
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+#import "WebNetscapePluginPackage.h"
+
+#import "WebTypesInternal.h"
+#import "WebKitLogging.h"
+#import "WebKitNSStringExtras.h"
+#import "WebNSFileManagerExtras.h"
+#import "WebNSObjectExtras.h"
+#import "WebNetscapeDeprecatedFunctions.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;
+
+#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 *)[(NSString *)path fileSystemRepresentation], &fref, NULL);
+        if (err != noErr)
+            return -1;
+        
+        return FSOpenResFile(&fref, fsRdPerm);
+    }
+#endif
+
+    return CFBundleOpenBundleResourceMap(cfBundle.get());
+}
+
+- (void)closeResourceFile:(ResFileRefNum)resRef
+{
+#ifdef SUPPORT_CFM
+    if (!isBundle) {
+        CloseResFile(resRef);
+        return;
+    }
+#endif
+
+    CFBundleCloseBundleResourceMap(cfBundle.get(), 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;
+    
+    for (i=1; 1; i+=2) {
+        MIME = [[self stringForStringListID:MIMEListStringStringNumber
+                                   andIndex:i] lowercaseString];
+        if (!MIME)
+            break;
+
+        MimeClassInfo mimeClassInfo;
+        mimeClassInfo.type = String(MIME).lower();
+
+        extensionsList = [[self stringForStringListID:MIMEListStringStringNumber andIndex:i+1] lowercaseString];
+        if (extensionsList) {
+            extensions = [extensionsList componentsSeparatedByString:@","];
+            for (NSUInteger j = 0; j < [extensions count]; ++j)
+                mimeClassInfo.extensions.append((NSString *)[extensions objectAtIndex:j]);
+        }
+        
+        description = [self stringForStringListID:MIMEDescriptionStringNumber
+                                         andIndex:pluginInfo.mimes.size() + 1];
+        mimeClassInfo.desc = description;
+
+        pluginInfo.mimes.append(mimeClassInfo);
+    }
+
+    NSString *filename = [(NSString *)path lastPathComponent];
+    pluginInfo.file = filename;
+    
+    description = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:1];
+    if (!description)
+        description = filename;
+    pluginInfo.desc = description;
+    
+    
+    NSString *theName = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:2];
+    if (!theName)
+        theName = filename;
+    pluginInfo.name = theName;
+    
+    [self closeResourceFile:resRef];
+    
+    return YES;
+}
+
+- (BOOL)_initWithPath:(NSString *)pluginPath
+{
+    resourceRef = -1;
+    
+    OSType type = 0;
+
+    if (cfBundle) {
+        // Bundle
+        CFBundleGetPackageInfo(cfBundle.get(), &type, NULL);
+#ifdef SUPPORT_CFM
+        isBundle = YES;
+#endif
+    } else {
+#ifdef SUPPORT_CFM
+        // Single-file plug-in with resource fork
+        NSString *destinationPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:path error:0];
+        type = [[[NSFileManager defaultManager] attributesOfItemAtPath:destinationPath error:0] 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 (cfBundle) {
+        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];
+        // 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 USE(PLUGIN_HOST_PROCESS)
+        RetainPtr<CFArrayRef> archs(AdoptCF, CFBundleCopyExecutableArchitectures(cfBundle.get()));
+        
+        if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureX86_64]])
+            pluginHostArchitecture = CPU_TYPE_X86_64;
+        else if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureI386]])
+            pluginHostArchitecture = CPU_TYPE_X86;
+        else
+            return NO;
+#else
+        if (![self isNativeLibraryData:data])
+            return NO;
+#endif
+    }
+
+    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;
+}
+
+#if USE(PLUGIN_HOST_PROCESS)
+- (cpu_type_t)pluginHostArchitecture
+{
+    return pluginHostArchitecture;
+}
+
+- (void)createPropertyListFile
+{
+    NetscapePluginHostManager::createPropertyListFile(path, pluginHostArchitecture);
+}
+
+#endif
+
+- (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 ([self bundleIdentifier] == "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)_tryLoad
+{
+    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, (NSString *)[self pluginInfo].name);
+
+    if (isLoaded)
+        return YES;
+    
+#ifdef SUPPORT_CFM
+    if (isBundle) {
+#endif
+        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;
+        
+#ifdef SUPPORT_CFM
+        if (isCFM) {
+            pluginMainFunc = (MainFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("main") );
+            if (!pluginMainFunc)
+                return NO;
+        } else {
+#endif
+            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;
+#ifdef SUPPORT_CFM
+        }
+    } else {
+        // single CFM file
+        FSSpec spec;
+        FSRef fref;
+        OSErr err;
+        
+        err = FSPathMakeRef((UInt8 *)[(NSString *)path fileSystemRepresentation], &fref, NULL);
+        if (err != noErr) {
+            LOG_ERROR("FSPathMakeRef failed. Error=%d", err);
+            return NO;
+        }
+        err = FSGetCatalogInfo(&fref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+        if (err != noErr) {
+            LOG_ERROR("FSGetCatalogInfo failed. Error=%d", err);
+            return NO;
+        }
+        err = WebGetDiskFragment(&spec, 0, kCFragGoesToEOF, nil, kPrivateCFragCopy, &connID, (Ptr *)&pluginMainFunc, nil);
+        if (err != noErr) {
+            LOG_ERROR("WebGetDiskFragment failed. Error=%d", err);
+            return NO;
+        }
+#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) {
+            return NO;
+        }
+
+        // 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.pluginthreadasynccall = (NPN_PluginThreadAsyncCallProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PluginThreadAsyncCall);
+        browserFuncs.getvalueforurl = (NPN_GetValueForURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetValueForURL);
+        browserFuncs.setvalueforurl = (NPN_SetValueForURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_SetValueForURL);
+        browserFuncs.getauthenticationinfo = (NPN_GetAuthenticationInfoProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetAuthenticationInfo);
+        browserFuncs.scheduletimer = (NPN_ScheduleTimerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ScheduleTimer);
+        browserFuncs.unscheduletimer = (NPN_UnscheduleTimerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_UnscheduleTimer);
+        browserFuncs.popupcontextmenu = (NPN_PopUpContextMenuProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PopUpContextMenu);
+        browserFuncs.convertpoint = (NPN_ConvertPointProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ConvertPoint);
+        
+        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.intfromidentifier = (NPN_IntFromIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_IntFromIdentifier);
+        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.hasmethod = (NPN_HasMethodProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_HasProperty);
+        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.hasproperty = (NPN_HasPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_HasProperty);
+        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);
+        browserFuncs.construct = (NPN_ConstructProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Construct);
+        
+        [self _applyDjVuWorkaround];
+        
+#if !LOG_DISABLED
+        CFAbsoluteTime mainStart = CFAbsoluteTimeGetCurrent();
+#endif
+        LOG(Plugins, "%f main timing started", mainStart);
+        NPP_ShutdownProcPtr shutdownFunction;
+        npErr = pluginMainFunc(&browserFuncs, &pluginFuncs, &shutdownFunction);
+        NP_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(reinterpret_cast<void*>(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 && equalIgnoringCase(pluginInfo.file, RealPlayerPluginFilename))
+                [self launchRealPlayer];
+            return NO;
+        }
+#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);
+        
+        pluginFuncs.newp = (NPP_NewProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newp);
+        pluginFuncs.destroy = (NPP_DestroyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroy);
+        pluginFuncs.setwindow = (NPP_SetWindowProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setwindow);
+        pluginFuncs.newstream = (NPP_NewStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newstream);
+        pluginFuncs.destroystream = (NPP_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroystream);
+        pluginFuncs.asfile = (NPP_StreamAsFileProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.asfile);
+        pluginFuncs.writeready = (NPP_WriteReadyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.writeready);
+        pluginFuncs.write = (NPP_WriteProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.write);
+        pluginFuncs.print = (NPP_PrintProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.print);
+        pluginFuncs.event = (NPP_HandleEventProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.event);
+        pluginFuncs.urlnotify = (NPP_URLNotifyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.urlnotify);
+        pluginFuncs.getvalue = (NPP_GetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.getvalue);
+        pluginFuncs.setvalue = (NPP_SetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setvalue);
+
+        // LiveConnect support
+        pluginFuncs.javaClass = (JRIGlobalRef)functionPointerForTVector((TransitionVector)pluginFuncs.javaClass);
+        if (pluginFuncs.javaClass) {
+            LOG(LiveConnect, "%@:  CFM entry point for NPP_GetJavaClass = %p", (NSString *)[self pluginInfo].name, pluginFuncs.javaClass);
+        } else {
+            LOG(LiveConnect, "%@:  no entry point for NPP_GetJavaClass", (NSString *)[self pluginInfo].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.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;
+        
+        [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)
+            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 (pluginFuncs.javaClass)
+            LOG(LiveConnect, "%@:  mach-o entry point for NPP_GetJavaClass = %p", (NSString *)[self pluginInfo].name, pluginFuncs.javaClass);
+        else
+            LOG(LiveConnect, "%@:  no entry point for NPP_GetJavaClass", (NSString *)[self pluginInfo].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 YES;
+}
+
+- (BOOL)load
+{    
+    if ([self _tryLoad])
+        return [super load];
+
+    [self _unloadWithShutdown:NO];
+    return NO;
+}
+
+- (NPPluginFuncs *)pluginFuncs
+{
+    return &pluginFuncs;
+}
+
+- (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
+
+#ifdef SUPPORT_CFM
+
+// function pointer converters
+
+FunctionPointer functionPointerForTVector(TransitionVector tvp)
+{
+    const uint32_t temp[6] = {0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420};
+    uint32_t *newGlue = NULL;
+
+    if (tvp != NULL) {
+        newGlue = (uint32_t *)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 %@...", (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];
+
+#ifdef SUPPORT_CFM
+    if (!isBundle)
+        WebCloseConnection(&connID);
+#endif
+
+    LOG(Plugins, "Plugin Unloaded");
+    isLoaded = NO;
+}
+
+@end
+#endif