f6213f377df76d1231e2e8cfd192cf2158dfaf9f
[WebKit.git] / Source / WebKitLegacy / mac / Plugins / WebNetscapePluginPackage.mm
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 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 <WebCore/npruntime_impl.h>
38 #import <wtf/RetainPtr.h>
39
40 #if USE(PLUGIN_HOST_PROCESS)
41 #import "NetscapePluginHostManager.h"
42
43 using namespace WebKit;
44 #endif
45
46 using namespace WebCore;
47
48 @interface WebNetscapePluginPackage (Internal)
49 - (void)_unloadWithShutdown:(BOOL)shutdown;
50 @end
51
52 @implementation WebNetscapePluginPackage
53
54 - (ResFileRefNum)openResourceFile
55 {
56     return CFBundleOpenBundleResourceMap(cfBundle.get());
57 }
58
59 - (void)closeResourceFile:(ResFileRefNum)resRef
60 {
61     CFBundleCloseBundleResourceMap(cfBundle.get(), resRef);
62 }
63
64 - (BOOL)_initWithPath:(NSString *)pluginPath
65 {
66     resourceRef = -1;
67     
68     OSType type = 0;
69
70     if (!cfBundle)
71         return NO;
72
73     CFBundleGetPackageInfo(cfBundle.get(), &type, NULL);
74     
75     if (type != FOUR_CHAR_CODE('BRPL'))
76         return NO;
77
78 #if USE(PLUGIN_HOST_PROCESS)
79     RetainPtr<CFArrayRef> archs = adoptCF(CFBundleCopyExecutableArchitectures(cfBundle.get()));
80
81     if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureX86_64]])
82         pluginHostArchitecture = CPU_TYPE_X86_64;
83     else if ([(NSArray *)archs.get() containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureI386]])
84         pluginHostArchitecture = CPU_TYPE_X86;
85     else
86         return NO;
87 #else
88     RetainPtr<CFURLRef> executableURL = adoptCF(CFBundleCopyExecutableURL(cfBundle.get()));
89     if (!executableURL)
90         return NO;
91     NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[(NSURL *)executableURL.get() path]];
92     NSData *data = [executableFile readDataOfLength:512];
93     [executableFile closeFile];
94
95      if (![self isNativeLibraryData:data])
96          return NO;
97
98 #endif
99
100     if (![self getPluginInfoFromPLists])
101         return NO;
102     
103     return YES;
104 }
105
106 - (id)initWithPath:(NSString *)pluginPath
107 {
108     if (!(self = [super initWithPath:pluginPath]))
109         return nil;
110     
111     // Initializing a plugin package can cause it to be loaded.  If there was an error initializing the plugin package,
112     // ensure that it is unloaded before deallocating it (WebBasePluginPackage requires & asserts this).
113     if (![self _initWithPath:pluginPath]) {
114         [self _unloadWithShutdown:YES];
115         [self release];
116         return nil;
117     }
118         
119     return self;
120 }
121
122 #if USE(PLUGIN_HOST_PROCESS)
123 - (cpu_type_t)pluginHostArchitecture
124 {
125     return pluginHostArchitecture;
126 }
127
128 - (void)createPropertyListFile
129 {
130     NetscapePluginHostManager::singleton().createPropertyListFile(path, pluginHostArchitecture, [self bundleIdentifier]);
131 }
132
133 #endif
134
135 - (void)unload
136 {
137     [self _unloadWithShutdown:YES];
138 }
139
140 - (BOOL)_tryLoad
141 {
142     NP_GetEntryPointsFuncPtr NP_GetEntryPoints = NULL;
143     NP_InitializeFuncPtr NP_Initialize = NULL;
144     NPError npErr;
145
146 #if !LOG_DISABLED
147     CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
148     CFAbsoluteTime currentTime;
149     CFAbsoluteTime duration;
150 #endif
151     LOG(Plugins, "%f Load timing started for: %@", start, (NSString *)[self pluginInfo].name);
152
153     if (isLoaded)
154         return YES;
155     
156     if (!CFBundleLoadExecutable(cfBundle.get()))
157         return NO;
158 #if !LOG_DISABLED
159     currentTime = CFAbsoluteTimeGetCurrent();
160     duration = currentTime - start;
161 #endif
162     LOG(Plugins, "%f CFBundleLoadExecutable took %f seconds", currentTime, duration);
163     isLoaded = YES;
164
165     NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Initialize"));
166     NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_GetEntryPoints"));
167     NP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle.get(), CFSTR("NP_Shutdown"));
168     if (!NP_Initialize || !NP_GetEntryPoints || !NP_Shutdown)
169         return NO;
170
171 #pragma clang diagnostic push
172 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
173     // Plugins (at least QT) require that you call UseResFile on the resource file before loading it.
174     resourceRef = [self openResourceFile];
175     if (resourceRef != -1) {
176         UseResFile(resourceRef);
177     }
178 #pragma clang diagnostic pop
179
180     browserFuncs.version = NP_VERSION_MINOR;
181     browserFuncs.size = sizeof(NPNetscapeFuncs);
182     browserFuncs.geturl = NPN_GetURL;
183     browserFuncs.posturl = NPN_PostURL;
184     browserFuncs.requestread = NPN_RequestRead;
185     browserFuncs.newstream = NPN_NewStream;
186     browserFuncs.write = NPN_Write;
187     browserFuncs.destroystream = NPN_DestroyStream;
188     browserFuncs.status = NPN_Status;
189     browserFuncs.uagent = NPN_UserAgent;
190     browserFuncs.memalloc = NPN_MemAlloc;
191     browserFuncs.memfree = NPN_MemFree;
192     browserFuncs.memflush = NPN_MemFlush;
193     browserFuncs.reloadplugins = NPN_ReloadPlugins;
194     browserFuncs.geturlnotify = NPN_GetURLNotify;
195     browserFuncs.posturlnotify = NPN_PostURLNotify;
196     browserFuncs.getvalue = NPN_GetValue;
197     browserFuncs.setvalue = NPN_SetValue;
198     browserFuncs.invalidaterect = NPN_InvalidateRect;
199     browserFuncs.invalidateregion = NPN_InvalidateRegion;
200     browserFuncs.forceredraw = NPN_ForceRedraw;
201     browserFuncs.getJavaEnv = NPN_GetJavaEnv;
202     browserFuncs.getJavaPeer = NPN_GetJavaPeer;
203     browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
204     browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
205     browserFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
206     browserFuncs.getvalueforurl = NPN_GetValueForURL;
207     browserFuncs.setvalueforurl = NPN_SetValueForURL;
208     browserFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
209     browserFuncs.scheduletimer = NPN_ScheduleTimer;
210     browserFuncs.unscheduletimer = NPN_UnscheduleTimer;
211     browserFuncs.popupcontextmenu = NPN_PopUpContextMenu;
212     browserFuncs.convertpoint = NPN_ConvertPoint;
213
214     browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue;
215     browserFuncs.getstringidentifier = _NPN_GetStringIdentifier;
216     browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers;
217     browserFuncs.getintidentifier = _NPN_GetIntIdentifier;
218     browserFuncs.identifierisstring = _NPN_IdentifierIsString;
219     browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier;
220     browserFuncs.intfromidentifier = _NPN_IntFromIdentifier;
221     browserFuncs.createobject = _NPN_CreateObject;
222     browserFuncs.retainobject = _NPN_RetainObject;
223     browserFuncs.releaseobject = _NPN_ReleaseObject;
224     browserFuncs.hasmethod = _NPN_HasMethod;
225     browserFuncs.invoke = _NPN_Invoke;
226     browserFuncs.invokeDefault = _NPN_InvokeDefault;
227     browserFuncs.evaluate = _NPN_Evaluate;
228     browserFuncs.hasproperty = _NPN_HasProperty;
229     browserFuncs.getproperty = _NPN_GetProperty;
230     browserFuncs.setproperty = _NPN_SetProperty;
231     browserFuncs.removeproperty = _NPN_RemoveProperty;
232     browserFuncs.setexception = _NPN_SetException;
233     browserFuncs.enumerate = _NPN_Enumerate;
234     browserFuncs.construct = _NPN_Construct;
235
236 #if !LOG_DISABLED
237     CFAbsoluteTime initializeStart = CFAbsoluteTimeGetCurrent();
238 #endif
239     LOG(Plugins, "%f NP_Initialize timing started", initializeStart);
240     npErr = NP_Initialize(&browserFuncs);
241     if (npErr != NPERR_NO_ERROR)
242         return NO;
243 #if !LOG_DISABLED
244     currentTime = CFAbsoluteTimeGetCurrent();
245     duration = currentTime - initializeStart;
246 #endif
247     LOG(Plugins, "%f NP_Initialize took %f seconds", currentTime, duration);
248
249     pluginFuncs.size = sizeof(NPPluginFuncs);
250
251     npErr = NP_GetEntryPoints(&pluginFuncs);
252     if (npErr != NPERR_NO_ERROR)
253         return NO;
254
255     pluginSize = pluginFuncs.size;
256     pluginVersion = pluginFuncs.version;
257
258 #if !LOG_DISABLED
259     currentTime = CFAbsoluteTimeGetCurrent();
260     duration = currentTime - start;
261 #endif
262     LOG(Plugins, "%f Total load time: %f seconds", currentTime, duration);
263
264     return YES;
265 }
266
267 - (BOOL)load
268 {    
269     if ([self _tryLoad])
270         return [super load];
271
272     [self _unloadWithShutdown:NO];
273     return NO;
274 }
275
276 - (NPPluginFuncs *)pluginFuncs
277 {
278     return &pluginFuncs;
279 }
280
281 - (NPNetscapeFuncs *)browserFuncs
282 {
283     return &browserFuncs;
284 }
285
286 - (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
287 {
288     [super wasRemovedFromPluginDatabase:database];
289     
290     // Unload when removed from final plug-in database
291     if ([pluginDatabases count] == 0)
292         [self _unloadWithShutdown:YES];
293 }
294
295 - (void)open
296 {
297     instanceCount++;
298     
299     // Handle the case where all instances close a plug-in package, but another
300     // instance opens the package before it is unloaded (which only happens when
301     // the plug-in database is refreshed)
302     needsUnload = NO;
303     
304     if (!isLoaded) {
305         // Should load when the first instance opens the plug-in package
306         ASSERT(instanceCount == 1);
307         [self load];
308     }
309 }
310
311 - (void)close
312 {
313     ASSERT(instanceCount > 0);
314     instanceCount--;
315     if (instanceCount == 0 && needsUnload)
316         [self _unloadWithShutdown:YES];
317 }
318
319
320 - (BOOL)supportsSnapshotting
321 {
322     if ([self bundleIdentifier] != "com.macromedia.Flash Player.plugin")
323         return YES;
324     
325     // Flash has a bogus Info.plist entry for CFBundleVersionString, so use CFBundleShortVersionString.
326     NSString *versionString = (NSString *)CFDictionaryGetValue(CFBundleGetInfoDictionary(cfBundle.get()), CFSTR("CFBundleShortVersionString"));
327     
328     if (![versionString hasPrefix:@"10.1"])
329         return YES;
330     
331     // Some prerelease versions of Flash 10.1 crash when sent a drawRect event using the CA drawing model: <rdar://problem/7739922>
332     return CFStringCompare((CFStringRef)versionString, CFSTR("10.1.53.60"), kCFCompareNumerically) != kCFCompareLessThan;
333 }
334
335 @end
336
337 @implementation WebNetscapePluginPackage (Internal)
338
339 - (void)_unloadWithShutdown:(BOOL)shutdown
340 {
341     if (!isLoaded)
342         return;
343     
344     LOG(Plugins, "Unloading %@...", (NSString *)pluginInfo.name);
345
346     // Cannot unload a plug-in package while an instance is still using it
347     if (instanceCount > 0) {
348         needsUnload = YES;
349         return;
350     }
351
352     if (shutdown && NP_Shutdown)
353         NP_Shutdown();
354
355     if (resourceRef != -1)
356         [self closeResourceFile:resourceRef];
357
358     LOG(Plugins, "Plugin Unloaded");
359     isLoaded = NO;
360 }
361
362 @end
363 #endif