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 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 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 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 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 if (plist) 163 mimeDict = (CFDictionaryRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginMIMETypes")); 164 } 165 166 if (!mimeDict) 167 mimeDict = (CFDictionaryRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypes")); 168 169 if (mimeDict) { 170 CFIndex propCount = CFDictionaryGetCount(mimeDict.get()); 171 Vector<const void*, 128> keys(propCount); 172 Vector<const void*, 128> values(propCount); 173 CFDictionaryGetKeysAndValues(mimeDict.get(), keys.data(), values.data()); 174 for (int i = 0; i < propCount; ++i) { 175 String mimeType = (CFStringRef)keys[i]; 176 mimeType = mimeType.lower(); 177 178 WTF::RetainPtr<CFDictionaryRef> extensionsDict = (CFDictionaryRef)values[i]; 179 180 WTF::RetainPtr<CFNumberRef> enabled = (CFNumberRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeEnabled")); 181 if (enabled) { 182 int enabledValue = 0; 183 if (CFNumberGetValue(enabled.get(), kCFNumberIntType, &enabledValue) && enabledValue == 0) 184 continue; 185 } 186 187 Vector<String> mimeExtensions; 188 WTF::RetainPtr<CFArrayRef> extensions = (CFArrayRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginExtensions")); 189 if (extensions) { 190 CFIndex extensionCount = CFArrayGetCount(extensions.get()); 191 for (CFIndex i = 0; i < extensionCount; ++i) { 192 String extension =(CFStringRef)CFArrayGetValueAtIndex(extensions.get(), i); 193 extension = extension.lower(); 194 mimeExtensions.append(extension); 195 } 196 } 197 m_mimeToExtensions.set(mimeType, mimeExtensions); 198 199 String description = (CFStringRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeDescription")); 200 m_mimeToDescriptions.set(mimeType, description); 201 } 202 203 m_name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginName")); 204 m_description = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginDescription")); 205 206 } else { 207 int resFile = CFBundleOpenBundleResourceMap(m_module); 208 209 UseResFile(resFile); 210 211 Vector<String> mimes = stringListFromResourceId(MIMEListStringStringNumber); 212 213 if (mimes.size() % 2 != 0) 214 return false; 215 216 Vector<String> descriptions = stringListFromResourceId(MIMEDescriptionStringNumber); 217 if (descriptions.size() != mimes.size() / 2) 218 return false; 219 220 for (size_t i = 0; i < mimes.size(); i += 2) { 221 String mime = mimes[i].lower(); 222 Vector<String> extensions; 223 mimes[i + 1].lower().split(UChar(','), extensions); 224 225 m_mimeToExtensions.set(mime, extensions); 226 227 m_mimeToDescriptions.set(mime, descriptions[i / 2]); 228 } 229 230 Vector<String> names = stringListFromResourceId(PluginNameOrDescriptionStringNumber); 231 if (names.size() == 2) { 232 m_description = names[0]; 233 m_name = names[1]; 234 } 235 236 CFBundleCloseBundleResourceMap(m_module, resFile); 237 } 238 239 LOG(Plugins, "PluginPackage::fetchInfo(): Found plug-in '%s'", m_name.utf8().data()); 240 if (isPluginBlacklisted()) { 241 LOG(Plugins, "\tPlug-in is blacklisted!"); 242 return false; 243 } 244 245 return true; 246 } 247 248 bool PluginPackage::isPluginBlacklisted() 249 { 250 return false; 251 } 252 253 bool PluginPackage::load() 254 { 255 if (m_isLoaded) { 256 m_loadCount++; 257 return true; 258 } 259 260 WTF::RetainPtr<CFStringRef> path(AdoptCF, m_path.createCFString()); 261 WTF::RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), 262 kCFURLPOSIXPathStyle, false)); 263 m_module = CFBundleCreate(NULL, url.get()); 264 if (!m_module || !CFBundleLoadExecutable(m_module)) { 265 LOG(Plugins, "%s not loaded", m_path.utf8().data()); 266 return false; 267 } 268 269 m_isLoaded = true; 270 271 NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0; 272 NP_InitializeFuncPtr NP_Initialize; 273 NPError npErr; 274 275 NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Initialize")); 276 NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_GetEntryPoints")); 277 m_NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Shutdown")); 278 279 if (!NP_Initialize || !NP_GetEntryPoints || !m_NPP_Shutdown) 280 goto abort; 281 282 memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); 283 m_pluginFuncs.size = sizeof(m_pluginFuncs); 284 285 initializeBrowserFuncs(); 286 287 npErr = NP_Initialize(&m_browserFuncs); 288 LOG_NPERROR(npErr); 289 if (npErr != NPERR_NO_ERROR) 290 goto abort; 291 292 npErr = NP_GetEntryPoints(&m_pluginFuncs); 293 LOG_NPERROR(npErr); 294 if (npErr != NPERR_NO_ERROR) 295 goto abort; 296 297 m_loadCount++; 298 return true; 299 300 abort: 301 unloadWithoutShutdown(); 302 return false; 303 } 304 305 } // namespace WebCore 306 307 #else 308 309 #include "../PluginPackageNone.cpp" 310 311 #endif // !__LP64__ 312