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