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