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