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
29#if ENABLE(NETSCAPE_PLUGIN_API)
30#import "WebNetscapePluginPackage.h"
31
32#import "WebTypesInternal.h"
33#import "WebKitLogging.h"
34#import "WebKitNSStringExtras.h"
35#import "WebNSFileManagerExtras.h"
36#import "WebNSObjectExtras.h"
37#import "WebNetscapeDeprecatedFunctions.h"
38#import <WebCore/npruntime_impl.h>
39#import <wtf/RetainPtr.h>
40
41#if USE(PLUGIN_HOST_PROCESS)
42#import "NetscapePluginHostManager.h"
43
44using namespace WebKit;
45#endif
46
47using namespace WebCore;
48
49#ifdef SUPPORT_CFM
50typedef void (* FunctionPointer)(void);
51typedef void (* TransitionVector)(void);
52static FunctionPointer functionPointerForTVector(TransitionVector);
53static TransitionVector tVectorForFunctionPointer(FunctionPointer);
54#endif
55
56#define PluginNameOrDescriptionStringNumber     126
57#define MIMEDescriptionStringNumber             127
58#define MIMEListStringStringNumber              128
59
60#define RealPlayerAppIndentifier                @"com.RealNetworks.RealOne Player"
61#define RealPlayerPluginFilename                "RealPlayer Plugin"
62
63@interface WebNetscapePluginPackage (Internal)
64- (void)_unloadWithShutdown:(BOOL)shutdown;
65@end
66
67@implementation WebNetscapePluginPackage
68
69#ifndef __LP64__
70+ (void)initialize
71{
72    // The Shockwave plugin requires a valid file in CurApRefNum.
73    // But it doesn't seem to matter what file it is.
74    // If we're called inside a Cocoa application which won't have a
75    // CurApRefNum, we set it to point to the system resource file.
76
77    // Call CurResFile before testing the result of WebLMGetCurApRefNum.
78    // If we are called before the bundle resource map has been opened
79    // for a Carbon application (or a Cocoa app with Resource Manager
80    // resources) we *do not* want to set CurApRefNum to point at the
81    // system resource file. CurResFile triggers Resource Manager lazy
82    // initialization, and will open the bundle resource map as necessary.
83
84    CurResFile();
85
86    if (WebLMGetCurApRefNum() == -1) {
87        // To get the refNum for the system resource file, we have to do
88        // UseResFile(kSystemResFile) and then look at CurResFile().
89        short savedCurResFile = CurResFile();
90        UseResFile(kSystemResFile);
91        WebLMSetCurApRefNum(CurResFile());
92        UseResFile(savedCurResFile);
93    }
94}
95#endif
96
97- (ResFileRefNum)openResourceFile
98{
99#ifdef SUPPORT_CFM
100    if (!isBundle) {
101        FSRef fref;
102        OSErr err = FSPathMakeRef((const UInt8 *)[(NSString *)path fileSystemRepresentation], &fref, NULL);
103        if (err != noErr)
104            return -1;
105
106        return FSOpenResFile(&fref, fsRdPerm);
107    }
108#endif
109
110    return CFBundleOpenBundleResourceMap(cfBundle.get());
111}
112
113- (void)closeResourceFile:(ResFileRefNum)resRef
114{
115#ifdef SUPPORT_CFM
116    if (!isBundle) {
117        CloseResFile(resRef);
118        return;
119    }
120#endif
121
122    CFBundleCloseBundleResourceMap(cfBundle.get(), resRef);
123}
124
125- (NSString *)stringForStringListID:(SInt16)stringListID andIndex:(SInt16)index
126{
127    // Get resource, and dereference the handle.
128    Handle stringHandle = Get1Resource('STR#', stringListID);
129    if (stringHandle == NULL) {
130        return nil;
131    }
132    unsigned char *p = (unsigned char *)*stringHandle;
133    if (!p)
134        return nil;
135
136    // Check the index against the length of the string list, then skip the length.
137    if (index < 1 || index > *(SInt16 *)p)
138        return nil;
139    p += sizeof(SInt16);
140
141    // Skip any strings that come before the one we are looking for.
142    while (--index)
143        p += 1 + *p;
144
145    // Convert the one we found into an NSString.
146    return [[[NSString alloc] initWithBytes:(p + 1) length:*p encoding:[NSString _web_encodingForResource:stringHandle]] autorelease];
147}
148
149- (BOOL)getPluginInfoFromResources
150{
151    SInt16 resRef = [self openResourceFile];
152    if (resRef == -1)
153        return NO;
154
155    UseResFile(resRef);
156    if (ResError() != noErr)
157        return NO;
158
159    NSString *MIME, *extensionsList, *description;
160    NSArray *extensions;
161    unsigned i;
162
163    for (i=1; 1; i+=2) {
164        MIME = [[self stringForStringListID:MIMEListStringStringNumber
165                                   andIndex:i] lowercaseString];
166        if (!MIME)
167            break;
168
169        MimeClassInfo mimeClassInfo;
170        mimeClassInfo.type = String(MIME).lower();
171
172        extensionsList = [[self stringForStringListID:MIMEListStringStringNumber andIndex:i+1] lowercaseString];
173        if (extensionsList) {
174            extensions = [extensionsList componentsSeparatedByString:@","];
175            for (NSUInteger j = 0; j < [extensions count]; ++j)
176                mimeClassInfo.extensions.append((NSString *)[extensions objectAtIndex:j]);
177        }
178
179        description = [self stringForStringListID:MIMEDescriptionStringNumber
180                                         andIndex:pluginInfo.mimes.size() + 1];
181        mimeClassInfo.desc = description;
182
183        pluginInfo.mimes.append(mimeClassInfo);
184    }
185
186    NSString *filename = [(NSString *)path lastPathComponent];
187    pluginInfo.file = filename;
188
189    description = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:1];
190    if (!description)
191        description = filename;
192    pluginInfo.desc = description;
193
194
195    NSString *theName = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:2];
196    if (!theName)
197        theName = filename;
198    pluginInfo.name = theName;
199
200    [self closeResourceFile:resRef];
201
202    return YES;
203}
204
205- (BOOL)_initWithPath:(NSString *)pluginPath
206{
207    resourceRef = -1;
208
209    OSType type = 0;
210
211    if (cfBundle) {
212        // Bundle
213        CFBundleGetPackageInfo(cfBundle.get(), &type, NULL);
214#ifdef SUPPORT_CFM
215        isBundle = YES;
216#endif
217    } else {
218#ifdef SUPPORT_CFM
219        // Single-file plug-in with resource fork
220        NSString *destinationPath = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:path error:0];
221        type = [[[NSFileManager defaultManager] attributesOfItemAtPath:destinationPath error:0] fileHFSTypeCode];
222        isBundle = NO;
223        isCFM = YES;
224#else
225        return NO;
226#endif
227    }
228
229    if (type != FOUR_CHAR_CODE('BRPL'))
230        return NO;
231
232    // Check if the executable is Mach-O or CFM.
233    if (cfBundle) {
234        RetainPtr<CFURLRef> executableURL(AdoptCF, CFBundleCopyExecutableURL(cfBundle.get()));
235        if (!executableURL)
236            return NO;
237        NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[(NSURL *)executableURL.get() path]];
238        NSData *data = [executableFile readDataOfLength:512];
239        [executableFile closeFile];
240        // Check the length of the data before calling memcmp. We think this fixes 3782543.
241        if (data == nil || [data length] < 8)
242            return NO;
243        BOOL hasCFMHeader = memcmp([data bytes], "Joy!peff", 8) == 0;
244#ifdef SUPPORT_CFM
245        isCFM = hasCFMHeader;
246#else
247        if (hasCFMHeader)
248            return NO;
249#endif
250
251#if USE(PLUGIN_HOST_PROCESS)
252        RetainPtr<CFArrayRef> archs(AdoptCF, CFBundleCopyExecutableArchitectures(cfBundle.get()));
253
254        if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureX86_64]])
255            pluginHostArchitecture = CPU_TYPE_X86_64;
256        else if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureI386]])
257            pluginHostArchitecture = CPU_TYPE_X86;
258        else
259            return NO;
260#else
261        if (![self isNativeLibraryData:data])
262            return NO;
263#endif
264    }
265
266    if (![self getPluginInfoFromPLists] && ![self getPluginInfoFromResources])
267        return NO;
268
269    return YES;
270}
271
272- (id)initWithPath:(NSString *)pluginPath
273{
274    if (!(self = [super initWithPath:pluginPath]))
275        return nil;
276
277    // Initializing a plugin package can cause it to be loaded.  If there was an error initializing the plugin package,
278    // ensure that it is unloaded before deallocating it (WebBasePluginPackage requires & asserts this).
279    if (![self _initWithPath:pluginPath]) {
280        [self _unloadWithShutdown:YES];
281        [self release];
282        return nil;
283    }
284
285    return self;
286}
287
288- (WebExecutableType)executableType
289{
290#ifdef SUPPORT_CFM
291    if (isCFM)
292        return WebCFMExecutableType;
293#endif
294    return WebMachOExecutableType;
295}
296
297#if USE(PLUGIN_HOST_PROCESS)
298- (cpu_type_t)pluginHostArchitecture
299{
300    return pluginHostArchitecture;
301}
302
303- (void)createPropertyListFile
304{
305    NetscapePluginHostManager::createPropertyListFile(path, pluginHostArchitecture);
306}
307
308#endif
309
310- (void)launchRealPlayer
311{
312    CFURLRef appURL = NULL;
313    OSStatus error = LSFindApplicationForInfo(kLSUnknownCreator, (CFStringRef)RealPlayerAppIndentifier, NULL, NULL, &appURL);
314    if (!error) {
315        LSLaunchURLSpec URLSpec;
316        bzero(&URLSpec, sizeof(URLSpec));
317        URLSpec.launchFlags = kLSLaunchDefaults | kLSLaunchDontSwitch;
318        URLSpec.appURL = appURL;
319        LSOpenFromURLSpec(&URLSpec, NULL);
320        CFRelease(appURL);
321    }
322}
323
324- (void)_applyDjVuWorkaround
325{
326    if (!cfBundle)
327        return;
328
329    if ([self bundleIdentifier] == "com.lizardtech.NPDjVu") {
330        // The DjVu plug-in will crash copying the vtable if it's too big so we cap it to
331        // what the plug-in expects here.
332        // size + version + 40 function pointers.
333        browserFuncs.size = 2 + 2 + sizeof(void *) * 40;
334    }
335
336}
337
338- (void)unload
339{
340    [self _unloadWithShutdown:YES];
341}
342
343- (BOOL)_tryLoad
344{
345    NP_GetEntryPointsFuncPtr NP_GetEntryPoints = NULL;
346    NP_InitializeFuncPtr NP_Initialize = NULL;
347    NPError npErr;
348
349#ifdef SUPPORT_CFM
350    MainFuncPtr pluginMainFunc = NULL;
351#endif
352
353#if !LOG_DISABLED
354    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
355    CFAbsoluteTime currentTime;
356    CFAbsoluteTime duration;
357#endif
358    LOG(Plugins, "%f Load timing started for: %@", start, (NSString *)[self pluginInfo].name);
359
360    if (isLoaded)
361        return YES;
362
363#ifdef SUPPORT_CFM
364    if (isBundle) {
365#endif
366        if (!CFBundleLoadExecutable(cfBundle.get()))
367            return NO;
368#if !LOG_DISABLED
369        currentTime = CFAbsoluteTimeGetCurrent();
370        duration = currentTime - start;
371#endif
372        LOG(Plugins, "%f CFBundleLoadExecutable took %f seconds", currentTime, duration);
373        isLoaded = YES;
374
375#ifdef SUPPORT_CFM
376        if (isCFM) {
377            pluginMainFunc = (MainFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("main") );
378            if (!pluginMainFunc)
379                return NO;
380        } else {
381#endif
382            NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Initialize"));
383            NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_GetEntryPoints"));
384            NP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Shutdown"));
385            if (!NP_Initialize || !NP_GetEntryPoints || !NP_Shutdown)
386                return NO;
387#ifdef SUPPORT_CFM
388        }
389    } else {
390        // single CFM file
391        FSSpec spec;
392        FSRef fref;
393        OSErr err;
394
395        err = FSPathMakeRef((UInt8 *)[(NSString *)path fileSystemRepresentation], &fref, NULL);
396        if (err != noErr) {
397            LOG_ERROR("FSPathMakeRef failed. Error=%d", err);
398            return NO;
399        }
400        err = FSGetCatalogInfo(&fref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
401        if (err != noErr) {
402            LOG_ERROR("FSGetCatalogInfo failed. Error=%d", err);
403            return NO;
404        }
405        err = WebGetDiskFragment(&spec, 0, kCFragGoesToEOF, nil, kPrivateCFragCopy, &connID, (Ptr *)&pluginMainFunc, nil);
406        if (err != noErr) {
407            LOG_ERROR("WebGetDiskFragment failed. Error=%d", err);
408            return NO;
409        }
410#if !LOG_DISABLED
411        currentTime = CFAbsoluteTimeGetCurrent();
412        duration = currentTime - start;
413#endif
414        LOG(Plugins, "%f WebGetDiskFragment took %f seconds", currentTime, duration);
415        isLoaded = YES;
416
417        pluginMainFunc = (MainFuncPtr)functionPointerForTVector((TransitionVector)pluginMainFunc);
418        if (!pluginMainFunc) {
419            return NO;
420        }
421
422        // NOTE: pluginMainFunc is freed after it is called. Be sure not to return before that.
423
424        isCFM = YES;
425    }
426#endif /* SUPPORT_CFM */
427
428    // Plugins (at least QT) require that you call UseResFile on the resource file before loading it.
429    resourceRef = [self openResourceFile];
430    if (resourceRef != -1) {
431        UseResFile(resourceRef);
432    }
433
434    // swap function tables
435#ifdef SUPPORT_CFM
436    if (isCFM) {
437        browserFuncs.version = NP_VERSION_MINOR;
438        browserFuncs.size = sizeof(NPNetscapeFuncs);
439        browserFuncs.geturl = (NPN_GetURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURL);
440        browserFuncs.posturl = (NPN_PostURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURL);
441        browserFuncs.requestread = (NPN_RequestReadProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_RequestRead);
442        browserFuncs.newstream = (NPN_NewStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_NewStream);
443        browserFuncs.write = (NPN_WriteProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Write);
444        browserFuncs.destroystream = (NPN_DestroyStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_DestroyStream);
445        browserFuncs.status = (NPN_StatusProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Status);
446        browserFuncs.uagent = (NPN_UserAgentProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_UserAgent);
447        browserFuncs.memalloc = (NPN_MemAllocProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemAlloc);
448        browserFuncs.memfree = (NPN_MemFreeProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFree);
449        browserFuncs.memflush = (NPN_MemFlushProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFlush);
450        browserFuncs.reloadplugins = (NPN_ReloadPluginsProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ReloadPlugins);
451        browserFuncs.geturlnotify = (NPN_GetURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURLNotify);
452        browserFuncs.posturlnotify = (NPN_PostURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURLNotify);
453        browserFuncs.getvalue = (NPN_GetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetValue);
454        browserFuncs.setvalue = (NPN_SetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_SetValue);
455        browserFuncs.invalidaterect = (NPN_InvalidateRectProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRect);
456        browserFuncs.invalidateregion = (NPN_InvalidateRegionProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRegion);
457        browserFuncs.forceredraw = (NPN_ForceRedrawProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ForceRedraw);
458        browserFuncs.getJavaEnv = (NPN_GetJavaEnvProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaEnv);
459        browserFuncs.getJavaPeer = (NPN_GetJavaPeerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaPeer);
460        browserFuncs.pushpopupsenabledstate = (NPN_PushPopupsEnabledStateProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PushPopupsEnabledState);
461        browserFuncs.poppopupsenabledstate = (NPN_PopPopupsEnabledStateProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PopPopupsEnabledState);
462        browserFuncs.pluginthreadasynccall = (NPN_PluginThreadAsyncCallProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PluginThreadAsyncCall);
463        browserFuncs.getvalueforurl = (NPN_GetValueForURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetValueForURL);
464        browserFuncs.setvalueforurl = (NPN_SetValueForURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_SetValueForURL);
465        browserFuncs.getauthenticationinfo = (NPN_GetAuthenticationInfoProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetAuthenticationInfo);
466        browserFuncs.scheduletimer = (NPN_ScheduleTimerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ScheduleTimer);
467        browserFuncs.unscheduletimer = (NPN_UnscheduleTimerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_UnscheduleTimer);
468        browserFuncs.popupcontextmenu = (NPN_PopUpContextMenuProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PopUpContextMenu);
469        browserFuncs.convertpoint = (NPN_ConvertPointProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ConvertPoint);
470
471        browserFuncs.releasevariantvalue = (NPN_ReleaseVariantValueProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseVariantValue);
472        browserFuncs.getstringidentifier = (NPN_GetStringIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifier);
473        browserFuncs.getstringidentifiers = (NPN_GetStringIdentifiersProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifiers);
474        browserFuncs.getintidentifier = (NPN_GetIntIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetIntIdentifier);
475        browserFuncs.identifierisstring = (NPN_IdentifierIsStringProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_IdentifierIsString);
476        browserFuncs.utf8fromidentifier = (NPN_UTF8FromIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_UTF8FromIdentifier);
477        browserFuncs.intfromidentifier = (NPN_IntFromIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_IntFromIdentifier);
478        browserFuncs.createobject = (NPN_CreateObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_CreateObject);
479        browserFuncs.retainobject = (NPN_RetainObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RetainObject);
480        browserFuncs.releaseobject = (NPN_ReleaseObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseObject);
481        browserFuncs.hasmethod = (NPN_HasMethodProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_HasProperty);
482        browserFuncs.invoke = (NPN_InvokeProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Invoke);
483        browserFuncs.invokeDefault = (NPN_InvokeDefaultProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_InvokeDefault);
484        browserFuncs.evaluate = (NPN_EvaluateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Evaluate);
485        browserFuncs.hasproperty = (NPN_HasPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_HasProperty);
486        browserFuncs.getproperty = (NPN_GetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetProperty);
487        browserFuncs.setproperty = (NPN_SetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetProperty);
488        browserFuncs.removeproperty = (NPN_RemovePropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RemoveProperty);
489        browserFuncs.setexception = (NPN_SetExceptionProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetException);
490        browserFuncs.enumerate = (NPN_EnumerateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Enumerate);
491        browserFuncs.construct = (NPN_ConstructProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Construct);
492
493        [self _applyDjVuWorkaround];
494
495#if !LOG_DISABLED
496        CFAbsoluteTime mainStart = CFAbsoluteTimeGetCurrent();
497#endif
498        LOG(Plugins, "%f main timing started", mainStart);
499        NPP_ShutdownProcPtr shutdownFunction;
500        npErr = pluginMainFunc(&browserFuncs, &pluginFuncs, &shutdownFunction);
501        NP_Shutdown = (NPP_ShutdownProcPtr)functionPointerForTVector((TransitionVector)shutdownFunction);
502        if (!isBundle)
503            // Don't free pluginMainFunc if we got it from a bundle because it is owned by CFBundle in that case.
504            free(reinterpret_cast<void*>(pluginMainFunc));
505
506        // Workaround for 3270576. The RealPlayer plug-in fails to load if its preference file is out of date.
507        // Launch the RealPlayer application to refresh the file.
508        if (npErr != NPERR_NO_ERROR) {
509            if (npErr == NPERR_MODULE_LOAD_FAILED_ERROR && equalIgnoringCase(pluginInfo.file, RealPlayerPluginFilename))
510                [self launchRealPlayer];
511            return NO;
512        }
513#if !LOG_DISABLED
514        currentTime = CFAbsoluteTimeGetCurrent();
515        duration = currentTime - mainStart;
516#endif
517        LOG(Plugins, "%f main took %f seconds", currentTime, duration);
518
519        pluginSize = pluginFuncs.size;
520        pluginVersion = pluginFuncs.version;
521        LOG(Plugins, "pluginMainFunc: %d, size=%d, version=%d", npErr, pluginSize, pluginVersion);
522
523        pluginFuncs.newp = (NPP_NewProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newp);
524        pluginFuncs.destroy = (NPP_DestroyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroy);
525        pluginFuncs.setwindow = (NPP_SetWindowProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setwindow);
526        pluginFuncs.newstream = (NPP_NewStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newstream);
527        pluginFuncs.destroystream = (NPP_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroystream);
528        pluginFuncs.asfile = (NPP_StreamAsFileProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.asfile);
529        pluginFuncs.writeready = (NPP_WriteReadyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.writeready);
530        pluginFuncs.write = (NPP_WriteProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.write);
531        pluginFuncs.print = (NPP_PrintProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.print);
532        pluginFuncs.event = (NPP_HandleEventProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.event);
533        pluginFuncs.urlnotify = (NPP_URLNotifyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.urlnotify);
534        pluginFuncs.getvalue = (NPP_GetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.getvalue);
535        pluginFuncs.setvalue = (NPP_SetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setvalue);
536
537        // LiveConnect support
538        pluginFuncs.javaClass = (JRIGlobalRef)functionPointerForTVector((TransitionVector)pluginFuncs.javaClass);
539        if (pluginFuncs.javaClass) {
540            LOG(LiveConnect, "%@:  CFM entry point for NPP_GetJavaClass = %p", (NSString *)[self pluginInfo].name, pluginFuncs.javaClass);
541        } else {
542            LOG(LiveConnect, "%@:  no entry point for NPP_GetJavaClass", (NSString *)[self pluginInfo].name);
543        }
544
545    } else {
546
547#endif
548
549        // no function pointer conversion necessary for Mach-O
550        browserFuncs.version = NP_VERSION_MINOR;
551        browserFuncs.size = sizeof(NPNetscapeFuncs);
552        browserFuncs.geturl = NPN_GetURL;
553        browserFuncs.posturl = NPN_PostURL;
554        browserFuncs.requestread = NPN_RequestRead;
555        browserFuncs.newstream = NPN_NewStream;
556        browserFuncs.write = NPN_Write;
557        browserFuncs.destroystream = NPN_DestroyStream;
558        browserFuncs.status = NPN_Status;
559        browserFuncs.uagent = NPN_UserAgent;
560        browserFuncs.memalloc = NPN_MemAlloc;
561        browserFuncs.memfree = NPN_MemFree;
562        browserFuncs.memflush = NPN_MemFlush;
563        browserFuncs.reloadplugins = NPN_ReloadPlugins;
564        browserFuncs.geturlnotify = NPN_GetURLNotify;
565        browserFuncs.posturlnotify = NPN_PostURLNotify;
566        browserFuncs.getvalue = NPN_GetValue;
567        browserFuncs.setvalue = NPN_SetValue;
568        browserFuncs.invalidaterect = NPN_InvalidateRect;
569        browserFuncs.invalidateregion = NPN_InvalidateRegion;
570        browserFuncs.forceredraw = NPN_ForceRedraw;
571        browserFuncs.getJavaEnv = NPN_GetJavaEnv;
572        browserFuncs.getJavaPeer = NPN_GetJavaPeer;
573        browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
574        browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
575        browserFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
576        browserFuncs.getvalueforurl = NPN_GetValueForURL;
577        browserFuncs.setvalueforurl = NPN_SetValueForURL;
578        browserFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
579        browserFuncs.scheduletimer = NPN_ScheduleTimer;
580        browserFuncs.unscheduletimer = NPN_UnscheduleTimer;
581        browserFuncs.popupcontextmenu = NPN_PopUpContextMenu;
582        browserFuncs.convertpoint = NPN_ConvertPoint;
583
584        browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue;
585        browserFuncs.getstringidentifier = _NPN_GetStringIdentifier;
586        browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers;
587        browserFuncs.getintidentifier = _NPN_GetIntIdentifier;
588        browserFuncs.identifierisstring = _NPN_IdentifierIsString;
589        browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier;
590        browserFuncs.intfromidentifier = _NPN_IntFromIdentifier;
591        browserFuncs.createobject = _NPN_CreateObject;
592        browserFuncs.retainobject = _NPN_RetainObject;
593        browserFuncs.releaseobject = _NPN_ReleaseObject;
594        browserFuncs.hasmethod = _NPN_HasMethod;
595        browserFuncs.invoke = _NPN_Invoke;
596        browserFuncs.invokeDefault = _NPN_InvokeDefault;
597        browserFuncs.evaluate = _NPN_Evaluate;
598        browserFuncs.hasproperty = _NPN_HasProperty;
599        browserFuncs.getproperty = _NPN_GetProperty;
600        browserFuncs.setproperty = _NPN_SetProperty;
601        browserFuncs.removeproperty = _NPN_RemoveProperty;
602        browserFuncs.setexception = _NPN_SetException;
603        browserFuncs.enumerate = _NPN_Enumerate;
604        browserFuncs.construct = _NPN_Construct;
605
606        [self _applyDjVuWorkaround];
607
608#if !LOG_DISABLED
609        CFAbsoluteTime initializeStart = CFAbsoluteTimeGetCurrent();
610#endif
611        LOG(Plugins, "%f NP_Initialize timing started", initializeStart);
612        npErr = NP_Initialize(&browserFuncs);
613        if (npErr != NPERR_NO_ERROR)
614            return NO;
615#if !LOG_DISABLED
616        currentTime = CFAbsoluteTimeGetCurrent();
617        duration = currentTime - initializeStart;
618#endif
619        LOG(Plugins, "%f NP_Initialize took %f seconds", currentTime, duration);
620
621        pluginFuncs.size = sizeof(NPPluginFuncs);
622
623        npErr = NP_GetEntryPoints(&pluginFuncs);
624        if (npErr != NPERR_NO_ERROR)
625            return NO;
626
627        pluginSize = pluginFuncs.size;
628        pluginVersion = pluginFuncs.version;
629
630        if (pluginFuncs.javaClass)
631            LOG(LiveConnect, "%@:  mach-o entry point for NPP_GetJavaClass = %p", (NSString *)[self pluginInfo].name, pluginFuncs.javaClass);
632        else
633            LOG(LiveConnect, "%@:  no entry point for NPP_GetJavaClass", (NSString *)[self pluginInfo].name);
634
635#ifdef SUPPORT_CFM
636    }
637#endif
638
639#if !LOG_DISABLED
640    currentTime = CFAbsoluteTimeGetCurrent();
641    duration = currentTime - start;
642#endif
643    LOG(Plugins, "%f Total load time: %f seconds", currentTime, duration);
644
645    return YES;
646}
647
648- (BOOL)load
649{
650    if ([self _tryLoad])
651        return [super load];
652
653    [self _unloadWithShutdown:NO];
654    return NO;
655}
656
657- (NPPluginFuncs *)pluginFuncs
658{
659    return &pluginFuncs;
660}
661
662- (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
663{
664    [super wasRemovedFromPluginDatabase:database];
665
666    // Unload when removed from final plug-in database
667    if ([pluginDatabases count] == 0)
668        [self _unloadWithShutdown:YES];
669}
670
671- (void)open
672{
673    instanceCount++;
674
675    // Handle the case where all instances close a plug-in package, but another
676    // instance opens the package before it is unloaded (which only happens when
677    // the plug-in database is refreshed)
678    needsUnload = NO;
679
680    if (!isLoaded) {
681        // Should load when the first instance opens the plug-in package
682        ASSERT(instanceCount == 1);
683        [self load];
684    }
685}
686
687- (void)close
688{
689    ASSERT(instanceCount > 0);
690    instanceCount--;
691    if (instanceCount == 0 && needsUnload)
692        [self _unloadWithShutdown:YES];
693}
694
695
696- (BOOL)supportsSnapshotting
697{
698    if ([self bundleIdentifier] != "com.macromedia.Flash Player.plugin")
699        return YES;
700
701    // Flash has a bogus Info.plist entry for CFBundleVersionString, so use CFBundleShortVersionString.
702    NSString *versionString = (NSString *)CFDictionaryGetValue(CFBundleGetInfoDictionary(cfBundle.get()), CFSTR("CFBundleShortVersionString"));
703
704    if (![versionString hasPrefix:@"10.1"])
705        return YES;
706
707    // Some prerelease versions of Flash 10.1 crash when sent a drawRect event using the CA drawing model: <rdar://problem/7739922>
708    return CFStringCompare((CFStringRef)versionString, CFSTR("10.1.53.60"), kCFCompareNumerically) != kCFCompareLessThan;
709}
710
711@end
712
713#ifdef SUPPORT_CFM
714
715// function pointer converters
716
717FunctionPointer functionPointerForTVector(TransitionVector tvp)
718{
719    const uint32_t temp[6] = {0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420};
720    uint32_t *newGlue = NULL;
721
722    if (tvp != NULL) {
723        newGlue = (uint32_t *)malloc(sizeof(temp));
724        if (newGlue != NULL) {
725            unsigned i;
726            for (i = 0; i < 6; i++) newGlue[i] = temp[i];
727            newGlue[0] |= ((uintptr_t)tvp >> 16);
728            newGlue[1] |= ((uintptr_t)tvp & 0xFFFF);
729            MakeDataExecutable(newGlue, sizeof(temp));
730        }
731    }
732
733    return (FunctionPointer)newGlue;
734}
735
736TransitionVector tVectorForFunctionPointer(FunctionPointer fp)
737{
738    FunctionPointer *newGlue = NULL;
739    if (fp != NULL) {
740        newGlue = (FunctionPointer *)malloc(2 * sizeof(FunctionPointer));
741        if (newGlue != NULL) {
742            newGlue[0] = fp;
743            newGlue[1] = NULL;
744        }
745    }
746    return (TransitionVector)newGlue;
747}
748
749#endif
750
751@implementation WebNetscapePluginPackage (Internal)
752
753- (void)_unloadWithShutdown:(BOOL)shutdown
754{
755    if (!isLoaded)
756        return;
757
758    LOG(Plugins, "Unloading %@...", (NSString *)pluginInfo.name);
759
760    // Cannot unload a plug-in package while an instance is still using it
761    if (instanceCount > 0) {
762        needsUnload = YES;
763        return;
764    }
765
766    if (shutdown && NP_Shutdown)
767        NP_Shutdown();
768
769    if (resourceRef != -1)
770        [self closeResourceFile:resourceRef];
771
772#ifdef SUPPORT_CFM
773    if (!isBundle)
774        WebCloseConnection(&connID);
775#endif
776
777    LOG(Plugins, "Plugin Unloaded");
778    isLoaded = NO;
779}
780
781@end
782#endif
783