|
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 #include "config.h" |
|
29 #include "PluginPackage.h" |
|
30 |
|
31 #include <wtf/RetainPtr.h> |
|
32 #include "MIMETypeRegistry.h" |
|
33 #include "npruntime_impl.h" |
|
34 #include "PluginDatabase.h" |
|
35 #include "PluginDebug.h" |
|
36 #include "WebCoreNSStringExtras.h" |
|
37 #include <wtf/text/CString.h> |
|
38 |
|
39 #include <CoreFoundation/CoreFoundation.h> |
|
40 |
|
41 #define PluginNameOrDescriptionStringNumber 126 |
|
42 #define MIMEDescriptionStringNumber 127 |
|
43 #define MIMEListStringStringNumber 128 |
|
44 |
|
45 namespace WebCore { |
|
46 |
|
47 void PluginPackage::determineQuirks(const String& mimeType) |
|
48 { |
|
49 if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) { |
|
50 // Because a single process cannot create multiple VMs, and we cannot reliably unload a |
|
51 // Java VM, we cannot unload the Java Plugin, or we'll lose reference to our only VM |
|
52 m_quirks.add(PluginQuirkDontUnloadPlugin); |
|
53 |
|
54 // Setting the window region to an empty region causes bad scrolling repaint problems |
|
55 // with the Java plug-in. |
|
56 m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling); |
|
57 } |
|
58 |
|
59 if (mimeType == "application/x-shockwave-flash") { |
|
60 // The flash plugin only requests windowless plugins if we return a mozilla user agent |
|
61 m_quirks.add(PluginQuirkWantsMozillaUserAgent); |
|
62 m_quirks.add(PluginQuirkThrottleInvalidate); |
|
63 m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages); |
|
64 m_quirks.add(PluginQuirkFlashURLNotifyBug); |
|
65 } |
|
66 |
|
67 } |
|
68 |
|
69 typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void); |
|
70 |
|
71 static WTF::RetainPtr<CFDictionaryRef> readPListFile(CFStringRef fileName, bool createFile, CFBundleRef bundle) |
|
72 { |
|
73 if (createFile) { |
|
74 BP_CreatePluginMIMETypesPreferencesFuncPtr funcPtr = |
|
75 (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("BP_CreatePluginMIMETypesPreferences")); |
|
76 if (funcPtr) |
|
77 funcPtr(); |
|
78 } |
|
79 |
|
80 WTF::RetainPtr<CFDictionaryRef> map; |
|
81 WTF::RetainPtr<CFURLRef> url = |
|
82 CFURLCreateWithFileSystemPath(kCFAllocatorDefault, fileName, kCFURLPOSIXPathStyle, false); |
|
83 |
|
84 CFDataRef resource = 0; |
|
85 SInt32 code; |
|
86 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url.get(), &resource, 0, 0, &code)) |
|
87 return map; |
|
88 |
|
89 WTF::RetainPtr<CFPropertyListRef> propertyList = |
|
90 CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource, kCFPropertyListImmutable, 0); |
|
91 |
|
92 CFRelease(resource); |
|
93 |
|
94 if (!propertyList) |
|
95 return map; |
|
96 |
|
97 if (CFGetTypeID(propertyList.get()) != CFDictionaryGetTypeID()) |
|
98 return map; |
|
99 |
|
100 map = static_cast<CFDictionaryRef>(static_cast<CFPropertyListRef>(propertyList.get())); |
|
101 return map; |
|
102 } |
|
103 |
|
104 static Vector<String> stringListFromResourceId(SInt16 id) |
|
105 { |
|
106 Vector<String> list; |
|
107 |
|
108 Handle handle = Get1Resource('STR#', id); |
|
109 if (!handle) |
|
110 return list; |
|
111 |
|
112 CFStringEncoding encoding = stringEncodingForResource(handle); |
|
113 |
|
114 unsigned char* p = (unsigned char*)*handle; |
|
115 if (!p) |
|
116 return list; |
|
117 |
|
118 SInt16 count = *(SInt16*)p; |
|
119 p += sizeof(SInt16); |
|
120 |
|
121 for (SInt16 i = 0; i < count; ++i) { |
|
122 unsigned char length = *p; |
|
123 WTF::RetainPtr<CFStringRef> str = CFStringCreateWithPascalString(0, p, encoding); |
|
124 list.append(str.get()); |
|
125 p += 1 + length; |
|
126 } |
|
127 |
|
128 return list; |
|
129 } |
|
130 |
|
131 bool PluginPackage::fetchInfo() |
|
132 { |
|
133 if (!load()) |
|
134 return false; |
|
135 |
|
136 WTF::RetainPtr<CFDictionaryRef> mimeDict; |
|
137 |
|
138 WTF::RetainPtr<CFTypeRef> mimeTypesFileName = CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypesFilename")); |
|
139 if (mimeTypesFileName && CFGetTypeID(mimeTypesFileName.get()) == CFStringGetTypeID()) { |
|
140 |
|
141 WTF::RetainPtr<CFStringRef> fileName = (CFStringRef)mimeTypesFileName.get(); |
|
142 WTF::RetainPtr<CFStringRef> homeDir = homeDirectoryPath().createCFString(); |
|
143 WTF::RetainPtr<CFStringRef> path = CFStringCreateWithFormat(0, 0, CFSTR("%@/Library/Preferences/%@"), homeDir.get(), fileName.get()); |
|
144 |
|
145 WTF::RetainPtr<CFDictionaryRef> plist = readPListFile(path.get(), /*createFile*/ false, m_module); |
|
146 if (plist) { |
|
147 // If the plist isn't localized, have the plug-in recreate it in the preferred language. |
|
148 WTF::RetainPtr<CFStringRef> localizationName = |
|
149 (CFStringRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginLocalizationName")); |
|
150 CFLocaleRef locale = CFLocaleCopyCurrent(); |
|
151 if (localizationName != CFLocaleGetIdentifier(locale)) |
|
152 plist = readPListFile(path.get(), /*createFile*/ true, m_module); |
|
153 |
|
154 CFRelease(locale); |
|
155 } else { |
|
156 // Plist doesn't exist, ask the plug-in to create it. |
|
157 plist = readPListFile(path.get(), /*createFile*/ true, m_module); |
|
158 } |
|
159 |
|
160 if (plist) |
|
161 mimeDict = (CFDictionaryRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginMIMETypes")); |
|
162 } |
|
163 |
|
164 if (!mimeDict) |
|
165 mimeDict = (CFDictionaryRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypes")); |
|
166 |
|
167 if (mimeDict) { |
|
168 CFIndex propCount = CFDictionaryGetCount(mimeDict.get()); |
|
169 Vector<const void*, 128> keys(propCount); |
|
170 Vector<const void*, 128> values(propCount); |
|
171 CFDictionaryGetKeysAndValues(mimeDict.get(), keys.data(), values.data()); |
|
172 for (int i = 0; i < propCount; ++i) { |
|
173 String mimeType = (CFStringRef)keys[i]; |
|
174 mimeType = mimeType.lower(); |
|
175 |
|
176 WTF::RetainPtr<CFDictionaryRef> extensionsDict = (CFDictionaryRef)values[i]; |
|
177 |
|
178 WTF::RetainPtr<CFNumberRef> enabled = (CFNumberRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeEnabled")); |
|
179 if (enabled) { |
|
180 int enabledValue = 0; |
|
181 if (CFNumberGetValue(enabled.get(), kCFNumberIntType, &enabledValue) && enabledValue == 0) |
|
182 continue; |
|
183 } |
|
184 |
|
185 Vector<String> mimeExtensions; |
|
186 WTF::RetainPtr<CFArrayRef> extensions = (CFArrayRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginExtensions")); |
|
187 if (extensions) { |
|
188 CFIndex extensionCount = CFArrayGetCount(extensions.get()); |
|
189 for (CFIndex i = 0; i < extensionCount; ++i) { |
|
190 String extension =(CFStringRef)CFArrayGetValueAtIndex(extensions.get(), i); |
|
191 extension = extension.lower(); |
|
192 mimeExtensions.append(extension); |
|
193 } |
|
194 } |
|
195 m_mimeToExtensions.set(mimeType, mimeExtensions); |
|
196 |
|
197 String description = (CFStringRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeDescription")); |
|
198 m_mimeToDescriptions.set(mimeType, description); |
|
199 } |
|
200 |
|
201 m_name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginName")); |
|
202 m_description = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginDescription")); |
|
203 |
|
204 } else { |
|
205 int resFile = CFBundleOpenBundleResourceMap(m_module); |
|
206 |
|
207 UseResFile(resFile); |
|
208 |
|
209 Vector<String> mimes = stringListFromResourceId(MIMEListStringStringNumber); |
|
210 |
|
211 if (mimes.size() % 2 != 0) |
|
212 return false; |
|
213 |
|
214 Vector<String> descriptions = stringListFromResourceId(MIMEDescriptionStringNumber); |
|
215 if (descriptions.size() != mimes.size() / 2) |
|
216 return false; |
|
217 |
|
218 for (size_t i = 0; i < mimes.size(); i += 2) { |
|
219 String mime = mimes[i].lower(); |
|
220 Vector<String> extensions; |
|
221 mimes[i + 1].lower().split(UChar(','), extensions); |
|
222 |
|
223 m_mimeToExtensions.set(mime, extensions); |
|
224 |
|
225 m_mimeToDescriptions.set(mime, descriptions[i / 2]); |
|
226 } |
|
227 |
|
228 Vector<String> names = stringListFromResourceId(PluginNameOrDescriptionStringNumber); |
|
229 if (names.size() == 2) { |
|
230 m_description = names[0]; |
|
231 m_name = names[1]; |
|
232 } |
|
233 |
|
234 CFBundleCloseBundleResourceMap(m_module, resFile); |
|
235 } |
|
236 |
|
237 LOG(Plugins, "PluginPackage::fetchInfo(): Found plug-in '%s'", m_name.utf8().data()); |
|
238 if (isPluginBlacklisted()) { |
|
239 LOG(Plugins, "\tPlug-in is blacklisted!"); |
|
240 return false; |
|
241 } |
|
242 |
|
243 return true; |
|
244 } |
|
245 |
|
246 bool PluginPackage::isPluginBlacklisted() |
|
247 { |
|
248 return false; |
|
249 } |
|
250 |
|
251 bool PluginPackage::load() |
|
252 { |
|
253 if (m_isLoaded) { |
|
254 m_loadCount++; |
|
255 return true; |
|
256 } |
|
257 |
|
258 WTF::RetainPtr<CFStringRef> path(AdoptCF, m_path.createCFString()); |
|
259 WTF::RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), |
|
260 kCFURLPOSIXPathStyle, false)); |
|
261 m_module = CFBundleCreate(NULL, url.get()); |
|
262 if (!m_module || !CFBundleLoadExecutable(m_module)) { |
|
263 LOG(Plugins, "%s not loaded", m_path.utf8().data()); |
|
264 return false; |
|
265 } |
|
266 |
|
267 m_isLoaded = true; |
|
268 |
|
269 NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0; |
|
270 NP_InitializeFuncPtr NP_Initialize; |
|
271 NPError npErr; |
|
272 |
|
273 NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Initialize")); |
|
274 NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_GetEntryPoints")); |
|
275 m_NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Shutdown")); |
|
276 |
|
277 if (!NP_Initialize || !NP_GetEntryPoints || !m_NPP_Shutdown) |
|
278 goto abort; |
|
279 |
|
280 memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); |
|
281 m_pluginFuncs.size = sizeof(m_pluginFuncs); |
|
282 |
|
283 initializeBrowserFuncs(); |
|
284 |
|
285 npErr = NP_Initialize(&m_browserFuncs); |
|
286 LOG_NPERROR(npErr); |
|
287 if (npErr != NPERR_NO_ERROR) |
|
288 goto abort; |
|
289 |
|
290 npErr = NP_GetEntryPoints(&m_pluginFuncs); |
|
291 LOG_NPERROR(npErr); |
|
292 if (npErr != NPERR_NO_ERROR) |
|
293 goto abort; |
|
294 |
|
295 m_loadCount++; |
|
296 return true; |
|
297 |
|
298 abort: |
|
299 unloadWithoutShutdown(); |
|
300 return false; |
|
301 } |
|
302 |
|
303 uint16_t PluginPackage::NPVersion() const |
|
304 { |
|
305 return NP_VERSION_MINOR; |
|
306 } |
|
307 } // namespace WebCore |