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