1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Collabora Ltd. All rights reserved.
4 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #ifndef __LP64__
29
30 #include "config.h"
31 #include "PluginPackage.h"
32
33 #include <wtf/RetainPtr.h>
34 #include "CString.h"
35 #include "MIMETypeRegistry.h"
36 #include "npruntime_impl.h"
37 #include "PluginDatabase.h"
38 #include "PluginDebug.h"
39 #include "WebCoreNSStringExtras.h"
40
41 #include <CoreFoundation/CoreFoundation.h>
42
43 #define PluginNameOrDescriptionStringNumber 126
44 #define MIMEDescriptionStringNumber 127
45 #define MIMEListStringStringNumber 128
46
47 namespace WebCore {
48
determineQuirks(const String & mimeType)49 void PluginPackage::determineQuirks(const String& mimeType)
50 {
51 if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) {
52 // Because a single process cannot create multiple VMs, and we cannot reliably unload a
53 // Java VM, we cannot unload the Java Plugin, or we'll lose reference to our only VM
54 m_quirks.add(PluginQuirkDontUnloadPlugin);
55
56 // Setting the window region to an empty region causes bad scrolling repaint problems
57 // with the Java plug-in.
58 m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling);
59 }
60
61 if (mimeType == "application/x-shockwave-flash") {
62 // The flash plugin only requests windowless plugins if we return a mozilla user agent
63 m_quirks.add(PluginQuirkWantsMozillaUserAgent);
64 m_quirks.add(PluginQuirkThrottleInvalidate);
65 m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages);
66 m_quirks.add(PluginQuirkFlashURLNotifyBug);
67 }
68
69 }
70
71 typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void);
72
readPListFile(CFStringRef fileName,bool createFile,CFBundleRef bundle)73 static WTF::RetainPtr<CFDictionaryRef> readPListFile(CFStringRef fileName, bool createFile, CFBundleRef bundle)
74 {
75 if (createFile) {
76 BP_CreatePluginMIMETypesPreferencesFuncPtr funcPtr =
77 (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("BP_CreatePluginMIMETypesPreferences"));
78 if (funcPtr)
79 funcPtr();
80 }
81
82 WTF::RetainPtr<CFDictionaryRef> map;
83 WTF::RetainPtr<CFURLRef> url =
84 CFURLCreateWithFileSystemPath(kCFAllocatorDefault, fileName, kCFURLPOSIXPathStyle, false);
85
86 CFDataRef resource = 0;
87 SInt32 code;
88 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url.get(), &resource, 0, 0, &code))
89 return map;
90
91 WTF::RetainPtr<CFPropertyListRef> propertyList =
92 CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource, kCFPropertyListImmutable, 0);
93
94 CFRelease(resource);
95
96 if (!propertyList)
97 return map;
98
99 if (CFGetTypeID(propertyList.get()) != CFDictionaryGetTypeID())
100 return map;
101
102 map = static_cast<CFDictionaryRef>(static_cast<CFPropertyListRef>(propertyList.get()));
103 return map;
104 }
105
stringListFromResourceId(SInt16 id)106 static Vector<String> stringListFromResourceId(SInt16 id)
107 {
108 Vector<String> list;
109
110 Handle handle = Get1Resource('STR#', id);
111 if (!handle)
112 return list;
113
114 CFStringEncoding encoding = stringEncodingForResource(handle);
115
116 unsigned char* p = (unsigned char*)*handle;
117 if (!p)
118 return list;
119
120 SInt16 count = *(SInt16*)p;
121 p += sizeof(SInt16);
122
123 for (SInt16 i = 0; i < count; ++i) {
124 unsigned char length = *p;
125 WTF::RetainPtr<CFStringRef> str = CFStringCreateWithPascalString(0, p, encoding);
126 list.append(str.get());
127 p += 1 + length;
128 }
129
130 return list;
131 }
132
fetchInfo()133 bool PluginPackage::fetchInfo()
134 {
135 if (!load())
136 return false;
137
138 WTF::RetainPtr<CFDictionaryRef> mimeDict;
139
140 WTF::RetainPtr<CFTypeRef> mimeTypesFileName = CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypesFilename"));
141 if (mimeTypesFileName && CFGetTypeID(mimeTypesFileName.get()) == CFStringGetTypeID()) {
142
143 WTF::RetainPtr<CFStringRef> fileName = (CFStringRef)mimeTypesFileName.get();
144 WTF::RetainPtr<CFStringRef> homeDir = homeDirectoryPath().createCFString();
145 WTF::RetainPtr<CFStringRef> path = CFStringCreateWithFormat(0, 0, CFSTR("%@/Library/Preferences/%@"), homeDir.get(), fileName.get());
146
147 WTF::RetainPtr<CFDictionaryRef> plist = readPListFile(path.get(), /*createFile*/ false, m_module);
148 if (plist) {
149 // If the plist isn't localized, have the plug-in recreate it in the preferred language.
150 WTF::RetainPtr<CFStringRef> localizationName =
151 (CFStringRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginLocalizationName"));
152 CFLocaleRef locale = CFLocaleCopyCurrent();
153 if (localizationName != CFLocaleGetIdentifier(locale))
154 plist = readPListFile(path.get(), /*createFile*/ true, m_module);
155
156 CFRelease(locale);
157 } else {
158 // Plist doesn't exist, ask the plug-in to create it.
159 plist = readPListFile(path.get(), /*createFile*/ true, m_module);
160 }
161
162 mimeDict = (CFDictionaryRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginMIMETypes"));
163 }
164
165 if (!mimeDict)
166 mimeDict = (CFDictionaryRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypes"));
167
168 if (mimeDict) {
169 CFIndex propCount = CFDictionaryGetCount(mimeDict.get());
170 Vector<const void*, 128> keys(propCount);
171 Vector<const void*, 128> values(propCount);
172 CFDictionaryGetKeysAndValues(mimeDict.get(), keys.data(), values.data());
173 for (int i = 0; i < propCount; ++i) {
174 String mimeType = (CFStringRef)keys[i];
175 mimeType = mimeType.lower();
176
177 WTF::RetainPtr<CFDictionaryRef> extensionsDict = (CFDictionaryRef)values[i];
178
179 WTF:RetainPtr<CFNumberRef> enabled = (CFNumberRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeEnabled"));
180 if (enabled) {
181 int enabledValue = 0;
182 if (CFNumberGetValue(enabled.get(), kCFNumberIntType, &enabledValue) && enabledValue == 0)
183 continue;
184 }
185
186 Vector<String> mimeExtensions;
187 WTF::RetainPtr<CFArrayRef> extensions = (CFArrayRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginExtensions"));
188 if (extensions) {
189 CFIndex extensionCount = CFArrayGetCount(extensions.get());
190 for (CFIndex i = 0; i < extensionCount; ++i) {
191 String extension =(CFStringRef)CFArrayGetValueAtIndex(extensions.get(), i);
192 extension = extension.lower();
193 mimeExtensions.append(extension);
194 }
195 }
196 m_mimeToExtensions.set(mimeType, mimeExtensions);
197
198 String description = (CFStringRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeDescription"));
199 m_mimeToDescriptions.set(mimeType, description);
200 }
201
202 m_name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginName"));
203 m_description = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginDescription"));
204
205 } else {
206 int resFile = CFBundleOpenBundleResourceMap(m_module);
207
208 UseResFile(resFile);
209
210 Vector<String> mimes = stringListFromResourceId(MIMEListStringStringNumber);
211
212 if (mimes.size() % 2 != 0)
213 return false;
214
215 Vector<String> descriptions = stringListFromResourceId(MIMEDescriptionStringNumber);
216 if (descriptions.size() != mimes.size() / 2)
217 return false;
218
219 for (size_t i = 0; i < mimes.size(); i += 2) {
220 String mime = mimes[i].lower();
221 Vector<String> extensions;
222 mimes[i + 1].lower().split(UChar(','), extensions);
223
224 m_mimeToExtensions.set(mime, extensions);
225
226 m_mimeToDescriptions.set(mime, descriptions[i / 2]);
227 }
228
229 Vector<String> names = stringListFromResourceId(PluginNameOrDescriptionStringNumber);
230 if (names.size() == 2) {
231 m_description = names[0];
232 m_name = names[1];
233 }
234
235 CFBundleCloseBundleResourceMap(m_module, resFile);
236 }
237
238 LOG(Plugins, "PluginPackage::fetchInfo(): Found plug-in '%s'", m_name.utf8().data());
239 if (isPluginBlacklisted()) {
240 LOG(Plugins, "\tPlug-in is blacklisted!");
241 return false;
242 }
243
244 return true;
245 }
246
isPluginBlacklisted()247 bool PluginPackage::isPluginBlacklisted()
248 {
249 if (name() == "Silverlight Plug-In" || name().startsWith("QuickTime Plug-in"))
250 return true;
251
252 return false;
253 }
254
load()255 bool PluginPackage::load()
256 {
257 if (m_isLoaded) {
258 m_loadCount++;
259 return true;
260 }
261
262 WTF::RetainPtr<CFStringRef> path(AdoptCF, m_path.createCFString());
263 WTF::RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(),
264 kCFURLPOSIXPathStyle, false));
265 m_module = CFBundleCreate(NULL, url.get());
266 if (!m_module || !CFBundleLoadExecutable(m_module)) {
267 LOG(Plugins, "%s not loaded", m_path.utf8().data());
268 return false;
269 }
270
271 m_isLoaded = true;
272
273 NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0;
274 NP_InitializeFuncPtr NP_Initialize;
275 NPError npErr;
276
277 NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Initialize"));
278 NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_GetEntryPoints"));
279 m_NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Shutdown"));
280
281 if (!NP_Initialize || !NP_GetEntryPoints || !m_NPP_Shutdown)
282 goto abort;
283
284 memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
285 m_pluginFuncs.size = sizeof(m_pluginFuncs);
286
287 initializeBrowserFuncs();
288
289 npErr = NP_Initialize(&m_browserFuncs);
290 LOG_NPERROR(npErr);
291 if (npErr != NPERR_NO_ERROR)
292 goto abort;
293
294 npErr = NP_GetEntryPoints(&m_pluginFuncs);
295 LOG_NPERROR(npErr);
296 if (npErr != NPERR_NO_ERROR)
297 goto abort;
298
299 m_loadCount++;
300 return true;
301
302 abort:
303 unloadWithoutShutdown();
304 return false;
305 }
306
307 } // namespace WebCore
308
309 #else
310
311 #include "../PluginPackageNone.cpp"
312
313 #endif // !__LP64__
314