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 308