Reviewed by Vicki.
[WebKit-https.git] / WebKit / Plugins.subproj / WebNetscapePluginPackage.m
1 /*
2         WebNetscapePluginPackage.m
3         Copyright (c) 2002, Apple, Inc. All rights reserved.
4 */
5
6 #import <WebKit/WebNetscapePluginPackage.h>
7
8 #import <WebKit/WebKitLogging.h>
9 #import <WebKit/WebKitNSStringExtras.h>
10 #import <WebKit/WebNSObjectExtras.h>
11
12 #import <JavaScriptCore/npruntime_impl.h>
13
14 typedef void (* FunctionPointer) (void);
15 typedef void (* TransitionVector) (void);
16 static FunctionPointer functionPointerForTVector(TransitionVector);
17 static TransitionVector tVectorForFunctionPointer(FunctionPointer);
18
19 #define PluginNameOrDescriptionStringNumber     126
20 #define MIMEDescriptionStringNumber             127
21 #define MIMEListStringStringNumber              128
22
23 #define RealPlayerAppIndentifier                @"com.RealNetworks.RealOne Player"
24 #define RealPlayerPluginFilename                @"RealPlayer Plugin"
25
26 @implementation WebNetscapePluginPackage
27
28 + (void)initialize
29 {
30     // The Shockwave plugin requires a valid file in CurApRefNum.
31     // But it doesn't seem to matter what file it is.
32     // If we're called inside a Cocoa application which won't have a
33     // CurApRefNum, we set it to point to the system resource file.
34     if (LMGetCurApRefNum() == -1) {
35         // To get the refNum for the system resource file, we have to do
36         // UseResFile(kSystemResFile) and then look at CurResFile().
37         short savedCurResFile = CurResFile();
38         UseResFile(kSystemResFile);
39         LMSetCurApRefNum(CurResFile());
40         UseResFile(savedCurResFile);
41     }
42 }
43
44 - (SInt16)openResourceFile
45 {
46     FSRef fref;
47     OSErr err;
48     
49     if (isBundle) {
50         return CFBundleOpenBundleResourceMap(cfBundle);
51     } else {
52         err = FSPathMakeRef((const UInt8 *)[path fileSystemRepresentation], &fref, NULL);
53         if (err != noErr) {
54             return -1;
55         }
56         
57         return FSOpenResFile(&fref, fsRdPerm);
58     }
59 }
60
61 - (void)closeResourceFile:(SInt16)resRef
62 {
63     if (isBundle) {
64         CFBundleCloseBundleResourceMap(cfBundle, resRef);
65     } else {
66         CloseResFile(resRef);
67     }
68 }
69
70 - (NSString *)stringForStringListID:(SInt16)stringListID andIndex:(SInt16)index
71 {
72     // Get resource, and dereference the handle.
73     Handle stringHandle = Get1Resource('STR#', stringListID);
74     if (stringHandle == NULL) {
75         return nil;
76     }
77     unsigned char *p = (unsigned char *)*stringHandle;
78     if (p == NULL) {
79         return nil;
80     }
81     
82     // Check the index against the length of the string list, then skip the length.
83     if (index < 1 || index > *(SInt16 *)p) {
84         return nil;
85     }
86     p += sizeof(SInt16);
87     
88     // Skip any strings that come before the one we are looking for.
89     while (--index)
90         p += 1 + *p;
91     
92     // Convert the one we found into an NSString.
93     return [[[NSString alloc] initWithBytes:(p + 1) length:*p encoding:[NSString _web_encodingForResource:stringHandle]] autorelease];
94 }
95
96 - (BOOL)getPluginInfoFromResources
97 {
98     SInt16 resRef = [self openResourceFile];
99     if (resRef == -1) {
100         return NO;
101     }
102     
103     UseResFile(resRef);
104     if (ResError() != noErr) {
105         return NO;
106     }
107
108     NSString *MIME, *extensionsList, *description;
109     NSArray *extensions;
110     NSRange r;
111     uint i;
112     
113     NSMutableDictionary *MIMEToExtensionsDictionary = [NSMutableDictionary dictionary];
114     NSMutableDictionary *MIMEToDescriptionDictionary = [NSMutableDictionary dictionary];
115
116     for (i=1; 1; i+=2) {
117         MIME = [[self stringForStringListID:MIMEListStringStringNumber
118                                    andIndex:i] lowercaseString];
119         if (!MIME) {
120             break;
121         }
122
123         // FIXME: Avoid mime types with semi-colons because KJS can't properly parse them using KWQKConfigBase
124         r = [MIME rangeOfString:@";"];
125         if (r.length > 0) {
126             continue;
127         }
128
129         extensionsList = [[self stringForStringListID:MIMEListStringStringNumber
130                                              andIndex:i+1] lowercaseString];
131         if (extensionsList) {
132             extensions = [extensionsList componentsSeparatedByString:@","];
133             [MIMEToExtensionsDictionary setObject:extensions forKey:MIME];
134         } else {
135             // DRM and WMP claim MIMEs without extensions. Use a @"" extension in this case.
136             [MIMEToExtensionsDictionary setObject:[NSArray arrayWithObject:@""] forKey:MIME];
137         }
138         
139         description = [self stringForStringListID:MIMEDescriptionStringNumber
140                                          andIndex:[MIMEToExtensionsDictionary count]];
141         if (description) {
142             [MIMEToDescriptionDictionary setObject:description forKey:MIME];
143         } else {
144             [MIMEToDescriptionDictionary setObject:@"" forKey:MIME];
145         }
146     }
147
148     [self setMIMEToDescriptionDictionary:MIMEToDescriptionDictionary];
149     [self setMIMEToExtensionsDictionary:MIMEToExtensionsDictionary];
150
151     NSString *filename = [self filename];
152     
153     description = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:1];
154     if (!description) {
155         description = filename;
156     }
157     [self setPluginDescription:description];
158     
159     
160     NSString *theName = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:2];
161     if (!theName) {
162         theName = filename;
163     }
164     [self setName:theName];
165     
166     [self closeResourceFile:resRef];
167     
168     return YES;
169 }
170
171 - initWithPath:(NSString *)pluginPath
172 {
173     [super initWithPath:pluginPath];
174
175     resourceRef = -1;
176     
177     OSType type = 0;
178
179     // Bundle
180     if (bundle) {
181         isBundle = YES;
182         CFBundleGetPackageInfo(cfBundle, &type, NULL);
183     }
184 #ifdef __ppc__
185     // Single-file plug-in with resource fork
186     else {
187         type = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] fileHFSTypeCode];
188         isBundle = NO;
189         isCFM = YES;
190     }
191 #endif
192     
193     if (type != FOUR_CHAR_CODE('BRPL')) {
194         [self release];
195         return nil;
196     }
197
198     // Check if the executable is Mach-O or CFM.
199     if (bundle) {
200         NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[bundle executablePath]];
201         NSData *data = [executableFile readDataOfLength:8];
202         [executableFile closeFile];
203         // Check the length of the data before calling memcmp. We think this fixes 3782543.
204         if (data == nil || [data length] < 8) {
205             [self release];
206             return nil;
207         }
208         isCFM = memcmp([data bytes], "Joy!peff", 8) == 0;
209 #ifndef __ppc__
210         // CFM is PPC-only.
211         if (isCFM) {
212             [self release];
213             return nil;
214         }
215 #endif
216     }
217
218     if (![self getPluginInfoFromPLists] && ![self getPluginInfoFromResources]) {
219         [self release];
220         return nil;
221     }
222
223     return self;
224 }
225
226 - (WebExecutableType)executableType
227 {
228     if (isCFM) {
229         return WebCFMExecutableType;
230     } else {
231         return WebMachOExecutableType;
232     }
233 }
234
235 - (BOOL)isLoaded
236 {
237     return isLoaded;
238 }
239
240 - (void)unloadWithoutShutdown
241 {
242     if (!isLoaded) {
243         return;
244     }
245
246     if (resourceRef != -1) {
247         [self closeResourceFile:resourceRef];
248     }
249
250     if (isBundle) {
251         CFBundleUnloadExecutable(cfBundle);
252     } else {
253         CloseConnection(&connID);
254     }
255
256     LOG(Plugins, "Plugin Unloaded");
257     isLoaded = NO;
258 }
259
260
261 - (void)launchRealPlayer
262 {
263     CFURLRef appURL = NULL;
264     OSStatus error = LSFindApplicationForInfo(kLSUnknownCreator, (CFStringRef)RealPlayerAppIndentifier, NULL, NULL, &appURL);
265     if (!error) {
266         LSLaunchURLSpec URLSpec;
267         bzero(&URLSpec, sizeof(URLSpec));
268         URLSpec.launchFlags = kLSLaunchDefaults | kLSLaunchDontSwitch;
269         URLSpec.appURL = appURL;
270         LSOpenFromURLSpec(&URLSpec, NULL);
271         CFRelease(appURL);
272     }
273 }
274
275 - (BOOL)load
276 {    
277     NP_GetEntryPointsFuncPtr NP_GetEntryPoints = NULL;
278     NP_InitializeFuncPtr NP_Initialize = NULL;
279     MainFuncPtr pluginMainFunc;
280     NPError npErr;
281     OSErr err;
282
283 #if !LOG_DISABLED
284     CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
285 #endif
286     LOG(Plugins, "%f Load timing started for: %@", start, [self name]);
287
288     if (isLoaded) {
289         return YES;
290     }
291     
292     if (isBundle) {
293         if (!CFBundleLoadExecutable(cfBundle)) {
294             goto abort;
295         }
296 #if !LOG_DISABLED
297         CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
298         CFAbsoluteTime duration = currentTime - start;
299 #endif
300         LOG(Plugins, "%f CFBundleLoadExecutable took %f seconds", currentTime, duration);
301         isLoaded = YES;
302         
303         if (isCFM) {
304             pluginMainFunc = (MainFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("main") );
305             if (!pluginMainFunc) {
306                 goto abort;
307             }
308         } else {
309             NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Initialize"));
310             NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_GetEntryPoints"));
311             NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Shutdown"));
312             if (!NP_Initialize || !NP_GetEntryPoints || !NPP_Shutdown) {
313                 goto abort;
314             }
315         }
316     } else {
317         // single CFM file
318         FSSpec spec;
319         FSRef fref;
320         
321         err = FSPathMakeRef((UInt8 *)[path fileSystemRepresentation], &fref, NULL);
322         if (err != noErr) {
323             ERROR("FSPathMakeRef failed. Error=%d", err);
324             goto abort;
325         }
326         err = FSGetCatalogInfo(&fref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
327         if (err != noErr) {
328             ERROR("FSGetCatalogInfo failed. Error=%d", err);
329             goto abort;
330         }
331         err = GetDiskFragment(&spec, 0, kCFragGoesToEOF, nil, kPrivateCFragCopy, &connID, (Ptr *)&pluginMainFunc, nil);
332         if (err != noErr) {
333             ERROR("GetDiskFragment failed. Error=%d", err);
334             goto abort;
335         }
336 #if !LOG_DISABLED
337         CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
338         CFAbsoluteTime duration = currentTime - start;
339 #endif
340         LOG(Plugins, "%f GetDiskFragment took %f seconds", currentTime, duration);
341         isLoaded = YES;
342         
343         pluginMainFunc = (MainFuncPtr)functionPointerForTVector((TransitionVector)pluginMainFunc);
344         if (!pluginMainFunc) {
345             goto abort;
346         }
347
348         // NOTE: pluginMainFunc is freed after it is called. Be sure not to return before that.
349         
350         isCFM = TRUE;
351     }
352     
353     // Plugins (at least QT) require that you call UseResFile on the resource file before loading it.
354     resourceRef = [self openResourceFile];
355     if (resourceRef != -1) {
356         UseResFile(resourceRef);
357     }
358     
359     // swap function tables
360     if (isCFM) {
361         browserFuncs.version = NP_VERSION_MINOR;
362         browserFuncs.size = sizeof(NPNetscapeFuncs);
363         browserFuncs.geturl = (NPN_GetURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURL);
364         browserFuncs.posturl = (NPN_PostURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURL);
365         browserFuncs.requestread = (NPN_RequestReadProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_RequestRead);
366         browserFuncs.newstream = (NPN_NewStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_NewStream);
367         browserFuncs.write = (NPN_WriteProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Write);
368         browserFuncs.destroystream = (NPN_DestroyStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_DestroyStream);
369         browserFuncs.status = (NPN_StatusProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Status);
370         browserFuncs.uagent = (NPN_UserAgentProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_UserAgent);
371         browserFuncs.memalloc = (NPN_MemAllocProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemAlloc);
372         browserFuncs.memfree = (NPN_MemFreeProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFree);
373         browserFuncs.memflush = (NPN_MemFlushProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFlush);
374         browserFuncs.reloadplugins = (NPN_ReloadPluginsProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ReloadPlugins);
375         browserFuncs.geturlnotify = (NPN_GetURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURLNotify);
376         browserFuncs.posturlnotify = (NPN_PostURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURLNotify);
377         browserFuncs.getvalue = (NPN_GetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetValue);
378         browserFuncs.setvalue = (NPN_SetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_SetValue);
379         browserFuncs.invalidaterect = (NPN_InvalidateRectProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRect);
380         browserFuncs.invalidateregion = (NPN_InvalidateRegionProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRegion);
381         browserFuncs.forceredraw = (NPN_ForceRedrawProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ForceRedraw);
382         browserFuncs.getJavaEnv = (NPN_GetJavaEnvProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaEnv);
383         browserFuncs.getJavaPeer = (NPN_GetJavaPeerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaPeer);
384
385         browserFuncs.releasevariantvalue = (NPN_ReleaseVariantValueProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseVariantValue);
386         browserFuncs.getstringidentifier = (NPN_GetStringIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifier);
387         browserFuncs.getstringidentifiers = (NPN_GetStringIdentifiersProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifiers);
388         browserFuncs.getintidentifier = (NPN_GetIntIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetIntIdentifier);
389         browserFuncs.identifierisstring = (NPN_IdentifierIsStringProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_IdentifierIsString);
390         browserFuncs.utf8fromidentifier = (NPN_UTF8FromIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_UTF8FromIdentifier);
391         browserFuncs.createobject = (NPN_CreateObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_CreateObject);
392         browserFuncs.retainobject = (NPN_RetainObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RetainObject);
393         browserFuncs.releaseobject = (NPN_ReleaseObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseObject);
394         browserFuncs.invoke = (NPN_InvokeProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Invoke);
395         browserFuncs.invokeDefault = (NPN_InvokeDefaultProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_InvokeDefault);
396         browserFuncs.evaluate = (NPN_EvaluateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Evaluate);
397         browserFuncs.getproperty = (NPN_GetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetProperty);
398         browserFuncs.setproperty = (NPN_SetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetProperty);
399         browserFuncs.removeproperty = (NPN_RemovePropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RemoveProperty);
400         browserFuncs.setexception = (NPN_SetExceptionProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetException);
401
402 #if !LOG_DISABLED
403         CFAbsoluteTime mainStart = CFAbsoluteTimeGetCurrent();
404 #endif
405         LOG(Plugins, "%f main timing started", mainStart);
406         NPP_ShutdownProcPtr shutdownFunction;
407         npErr = pluginMainFunc(&browserFuncs, &pluginFuncs, &shutdownFunction);
408         NPP_Shutdown = (NPP_ShutdownProcPtr)functionPointerForTVector((TransitionVector)shutdownFunction);
409         if (!isBundle) {
410             // Don't free pluginMainFunc if we got it from a bundle because it is owned by CFBundle in that case.
411             free(pluginMainFunc);
412         }
413         
414         // Workaround for 3270576. The RealPlayer plug-in fails to load if its preference file is out of date.
415         // Launch the RealPlayer application to refresh the file.
416         if (npErr != NPERR_NO_ERROR) {
417             if (npErr == NPERR_MODULE_LOAD_FAILED_ERROR && [[self filename] isEqualToString:RealPlayerPluginFilename]) {
418                 [self launchRealPlayer];
419             }
420             goto abort;
421         }
422 #if !LOG_DISABLED
423         CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
424         CFAbsoluteTime duration = currentTime - mainStart;
425 #endif
426         LOG(Plugins, "%f main took %f seconds", currentTime, duration);
427         
428         pluginSize = pluginFuncs.size;
429         pluginVersion = pluginFuncs.version;
430         LOG(Plugins, "pluginMainFunc: %d, size=%d, version=%d", npErr, pluginSize, pluginVersion);
431         
432         NPP_New = (NPP_NewProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newp);
433         NPP_Destroy = (NPP_DestroyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroy);
434         NPP_SetWindow = (NPP_SetWindowProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setwindow);
435         NPP_NewStream = (NPP_NewStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newstream);
436         NPP_DestroyStream = (NPP_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroystream);
437         NPP_StreamAsFile = (NPP_StreamAsFileProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.asfile);
438         NPP_WriteReady = (NPP_WriteReadyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.writeready);
439         NPP_Write = (NPP_WriteProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.write);
440         NPP_Print = (NPP_PrintProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.print);
441         NPP_HandleEvent = (NPP_HandleEventProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.event);
442         NPP_URLNotify = (NPP_URLNotifyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.urlnotify);
443         NPP_GetValue = (NPP_GetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.getvalue);
444         NPP_SetValue = (NPP_SetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setvalue);
445
446         // LiveConnect support
447         NPP_GetJavaClass = (NPP_GetJavaClassProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.javaClass);
448         if (NPP_GetJavaClass){
449             LOG(LiveConnect, "%@:  CFM entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass);
450         } else {
451             LOG(LiveConnect, "%@:  no entry point for NPP_GetJavaClass", [self name]);
452         }
453
454     } else {
455         // no function pointer conversion necessary for mach-o
456         browserFuncs.version = NP_VERSION_MINOR;
457         browserFuncs.size = sizeof(NPNetscapeFuncs);
458         browserFuncs.geturl = NPN_GetURL;
459         browserFuncs.posturl = NPN_PostURL;
460         browserFuncs.requestread = NPN_RequestRead;
461         browserFuncs.newstream = NPN_NewStream;
462         browserFuncs.write = NPN_Write;
463         browserFuncs.destroystream = NPN_DestroyStream;
464         browserFuncs.status = NPN_Status;
465         browserFuncs.uagent = NPN_UserAgent;
466         browserFuncs.memalloc = NPN_MemAlloc;
467         browserFuncs.memfree = NPN_MemFree;
468         browserFuncs.memflush = NPN_MemFlush;
469         browserFuncs.reloadplugins = NPN_ReloadPlugins;
470         browserFuncs.geturlnotify = NPN_GetURLNotify;
471         browserFuncs.posturlnotify = NPN_PostURLNotify;
472         browserFuncs.getvalue = NPN_GetValue;
473         browserFuncs.setvalue = NPN_SetValue;
474         browserFuncs.invalidaterect = NPN_InvalidateRect;
475         browserFuncs.invalidateregion = NPN_InvalidateRegion;
476         browserFuncs.forceredraw = NPN_ForceRedraw;
477         browserFuncs.getJavaEnv = NPN_GetJavaEnv;
478         browserFuncs.getJavaPeer = NPN_GetJavaPeer;
479
480         browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue;
481         browserFuncs.getstringidentifier = _NPN_GetStringIdentifier;
482         browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers;
483         browserFuncs.getintidentifier = _NPN_GetIntIdentifier;
484         browserFuncs.identifierisstring = _NPN_IdentifierIsString;
485         browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier;
486         browserFuncs.createobject = _NPN_CreateObject;
487         browserFuncs.retainobject = _NPN_RetainObject;
488         browserFuncs.releaseobject = _NPN_ReleaseObject;
489         browserFuncs.invoke = _NPN_Invoke;
490         browserFuncs.invokeDefault = _NPN_InvokeDefault;
491         browserFuncs.evaluate = _NPN_Evaluate;
492         browserFuncs.getproperty = _NPN_GetProperty;
493         browserFuncs.setproperty = _NPN_SetProperty;
494         browserFuncs.removeproperty = _NPN_RemoveProperty;
495         browserFuncs.setexception = _NPN_SetException;
496
497 #if !LOG_DISABLED
498         CFAbsoluteTime initializeStart = CFAbsoluteTimeGetCurrent();
499 #endif
500         LOG(Plugins, "%f NP_Initialize timing started", initializeStart);
501         npErr = NP_Initialize(&browserFuncs);
502         if (npErr != NPERR_NO_ERROR) {
503             goto abort;
504         }
505 #if !LOG_DISABLED
506         CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
507         CFAbsoluteTime duration = currentTime - initializeStart;
508 #endif
509         LOG(Plugins, "%f NP_Initialize took %f seconds", currentTime, duration);
510
511         npErr = NP_GetEntryPoints(&pluginFuncs);
512         if (npErr != NPERR_NO_ERROR) {
513             goto abort;
514         }
515         
516         pluginSize = pluginFuncs.size;
517         pluginVersion = pluginFuncs.version;
518         
519         NPP_New = pluginFuncs.newp;
520         NPP_Destroy = pluginFuncs.destroy;
521         NPP_SetWindow = pluginFuncs.setwindow;
522         NPP_NewStream = pluginFuncs.newstream;
523         NPP_DestroyStream = pluginFuncs.destroystream;
524         NPP_StreamAsFile = pluginFuncs.asfile;
525         NPP_WriteReady = pluginFuncs.writeready;
526         NPP_Write = pluginFuncs.write;
527         NPP_Print = pluginFuncs.print;
528         NPP_HandleEvent = pluginFuncs.event;
529         NPP_URLNotify = pluginFuncs.urlnotify;
530         NPP_GetValue = pluginFuncs.getvalue;
531         NPP_SetValue = pluginFuncs.setvalue;
532
533         // LiveConnect support
534         NPP_GetJavaClass = pluginFuncs.javaClass;
535         if (NPP_GetJavaClass){
536             LOG(LiveConnect, "%@:  mach-o entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass);
537         } else {
538             LOG(LiveConnect, "%@:  no entry point for NPP_GetJavaClass", [self name]);
539         }
540     }
541
542 #if !LOG_DISABLED
543     CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
544     CFAbsoluteTime duration = currentTime - start;
545 #endif
546     LOG(Plugins, "%f Total load time: %f seconds", currentTime, duration);
547
548     return [super load];
549
550 abort:
551     [self unloadWithoutShutdown];
552     return NO;
553 }
554     
555 - (void)unload
556 {
557     if (!isLoaded) {
558         return;
559     }
560     
561     LOG(Plugins, "Unloading %@...", name);
562
563     NPP_Shutdown();
564
565     [self unloadWithoutShutdown];
566 }
567
568 - (NPP_SetWindowProcPtr)NPP_SetWindow
569 {
570     return NPP_SetWindow;
571 }
572
573 - (NPP_NewProcPtr)NPP_New
574 {
575     return NPP_New;
576 }
577
578 - (NPP_DestroyProcPtr)NPP_Destroy
579 {
580     return NPP_Destroy;
581 }
582
583 - (NPP_NewStreamProcPtr)NPP_NewStream
584 {
585     return NPP_NewStream;
586 }
587
588 - (NPP_StreamAsFileProcPtr)NPP_StreamAsFile
589 {
590     return NPP_StreamAsFile;
591 }
592 - (NPP_DestroyStreamProcPtr)NPP_DestroyStream
593 {
594     return NPP_DestroyStream;
595 }
596
597 - (NPP_WriteReadyProcPtr)NPP_WriteReady
598 {
599     return NPP_WriteReady;
600 }
601 - (NPP_WriteProcPtr)NPP_Write
602 {
603     return NPP_Write;
604 }
605
606 - (NPP_HandleEventProcPtr)NPP_HandleEvent
607 {
608     return NPP_HandleEvent;
609 }
610
611 -(NPP_URLNotifyProcPtr)NPP_URLNotify
612 {
613     return NPP_URLNotify;
614 }
615
616 -(NPP_GetValueProcPtr)NPP_GetValue
617 {
618     return NPP_GetValue;
619 }
620
621 -(NPP_SetValueProcPtr)NPP_SetValue
622 {
623     return NPP_SetValue;
624 }
625
626 -(NPP_PrintProcPtr)NPP_Print
627 {
628     return NPP_Print;
629 }
630
631 @end
632
633
634 // function pointer converters
635
636 FunctionPointer functionPointerForTVector(TransitionVector tvp)
637 {
638     const uint32 temp[6] = {0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420};
639     uint32 *newGlue = NULL;
640
641     if (tvp != NULL) {
642         newGlue = (uint32 *)malloc(sizeof(temp));
643         if (newGlue != NULL) {
644             unsigned i;
645             for (i = 0; i < 6; i++) newGlue[i] = temp[i];
646             newGlue[0] |= ((UInt32)tvp >> 16);
647             newGlue[1] |= ((UInt32)tvp & 0xFFFF);
648             MakeDataExecutable(newGlue, sizeof(temp));
649         }
650     }
651     
652     return (FunctionPointer)newGlue;
653 }
654
655 TransitionVector tVectorForFunctionPointer(FunctionPointer fp)
656 {
657     FunctionPointer *newGlue = NULL;
658     if (fp != NULL) {
659         newGlue = (FunctionPointer *)malloc(2 * sizeof(FunctionPointer));
660         if (newGlue != NULL) {
661             newGlue[0] = fp;
662             newGlue[1] = NULL;
663         }
664     }
665     return (TransitionVector)newGlue;
666 }