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