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