1/* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Collabora Ltd. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "PluginPackage.h" 29 30#include "MIMETypeRegistry.h" 31#include "PluginDatabase.h" 32#include "PluginDebug.h" 33#include "npruntime_impl.h" 34#include <QFileInfo> 35#include <wtf/text/CString.h> 36 37namespace WebCore { 38 39bool PluginPackage::fetchInfo() 40{ 41 if (!m_module) { 42 if (isPluginBlacklisted()) 43 return false; 44 m_module = new QLibrary((QString)m_path); 45 m_module->setLoadHints(QLibrary::ResolveAllSymbolsHint); 46 if (!m_module->load()) { 47 LOG(Plugins, "%s not loaded (%s)", m_path.utf8().data(), 48 m_module->errorString().toLatin1().constData()); 49 return false; 50 } 51 // This is technically wrong (not matched by a decrement), but 52 // it matches the previous behavior (fetchInfo calling load) and 53 // prevents crashes in flash due to unload+load. 54 m_loadCount++; 55 } 56 57 NPP_GetValueProcPtr gv = (NPP_GetValueProcPtr)m_module->resolve("NP_GetValue"); 58 NP_GetMIMEDescriptionFuncPtr gm = 59 (NP_GetMIMEDescriptionFuncPtr)m_module->resolve("NP_GetMIMEDescription"); 60 if (!gm || !gv) 61 return false; 62 63 char *buf = 0; 64 NPError err = gv(0, NPPVpluginNameString, (void*) &buf); 65 if (err != NPERR_NO_ERROR) 66 return false; 67 68 m_name = String::fromUTF8(buf); 69 err = gv(0, NPPVpluginDescriptionString, (void*) &buf); 70 if (err != NPERR_NO_ERROR) 71 return false; 72 73 m_description = String::fromUTF8(buf); 74 determineModuleVersionFromDescription(); 75 76 setMIMEDescription(String::fromUTF8(gm())); 77 78 return true; 79} 80 81void PluginPackage::setMIMEDescription(const String& mimeDescription) 82{ 83 m_fullMIMEDescription = mimeDescription.lower(); 84 85 Vector<String> types; 86 mimeDescription.lower().split(UChar(';'), false, types); 87 for (unsigned i = 0; i < types.size(); ++i) { 88 Vector<String> mime; 89 types[i].split(UChar(':'), true, mime); 90 if (mime.size() > 0) { 91 Vector<String> exts; 92 if (mime.size() > 1) 93 mime[1].split(UChar(','), false, exts); 94 determineQuirks(mime[0]); 95 m_mimeToExtensions.add(mime[0], exts); 96 if (mime.size() > 2) 97 m_mimeToDescriptions.add(mime[0], mime[2]); 98 } 99 } 100} 101 102static NPError staticPluginQuirkRequiresGtkToolKit_NPN_GetValue(NPP instance, NPNVariable variable, void* value) 103{ 104 if (variable == NPNVToolkit) { 105 *static_cast<uint32_t*>(value) = 2; 106 return NPERR_NO_ERROR; 107 } 108 109 return NPN_GetValue(instance, variable, value); 110} 111 112static void initializeGtk(QLibrary* module = 0) 113{ 114 // Ensures missing Gtk initialization in some versions of Adobe's flash player 115 // plugin do not cause crashes. See BR# 40567, 44324, and 44405 for details. 116 if (module) { 117 typedef void *(*gtk_init_ptr)(int*, char***); 118 gtk_init_ptr gtkInit = (gtk_init_ptr)module->resolve("gtk_init"); 119 if (gtkInit) { 120 // Prevent gtk_init() from replacing the X error handlers, since the Gtk 121 // handlers abort when they receive an X error, thus killing the viewer. 122#ifdef Q_WS_X11 123 int (*old_error_handler)(Display*, XErrorEvent*) = XSetErrorHandler(0); 124 int (*old_io_error_handler)(Display*) = XSetIOErrorHandler(0); 125#endif 126 gtkInit(0, 0); 127#ifdef Q_WS_X11 128 XSetErrorHandler(old_error_handler); 129 XSetIOErrorHandler(old_io_error_handler); 130#endif 131 return; 132 } 133 } 134 135 QLibrary library(QLatin1String("libgtk-x11-2.0"), 0); 136 if (library.load()) { 137 typedef void *(*gtk_init_check_ptr)(int*, char***); 138 gtk_init_check_ptr gtkInitCheck = (gtk_init_check_ptr)library.resolve("gtk_init_check"); 139 // NOTE: We're using gtk_init_check() since gtk_init() calls exit() on failure. 140 if (gtkInitCheck) 141 (void) gtkInitCheck(0, 0); 142 } 143} 144 145bool PluginPackage::isPluginBlacklisted() 146{ 147 // TODO: enumerate all plugins that are incompatible with Qt5. 148 const QLatin1String pluginBlacklist[] = { 149 QLatin1String("skypebuttons") 150 }; 151 152 QString baseName = QFileInfo(static_cast<QString>(m_path)).baseName(); 153 for (unsigned i = 0; i < sizeof(pluginBlacklist) / sizeof(QLatin1String); ++i) { 154 if (baseName == pluginBlacklist[i]) 155 return true; 156 } 157 return false; 158} 159 160bool PluginPackage::load() 161{ 162 if (m_isLoaded) { 163 m_loadCount++; 164 return true; 165 } 166 167 if (isPluginBlacklisted()) 168 return false; 169 170 if (!m_module) { 171 m_module = new QLibrary((QString)m_path); 172 m_module->setLoadHints(QLibrary::ResolveAllSymbolsHint); 173 if (!m_module->load()) { 174 LOG(Plugins, "%s not loaded (%s)", m_path.utf8().data(), 175 m_module->errorString().toLatin1().constData()); 176 return false; 177 } 178 } 179 180 m_isLoaded = true; 181 182 NP_InitializeFuncPtr NP_Initialize; 183 NPError npErr; 184 185 NP_Initialize = (NP_InitializeFuncPtr)m_module->resolve("NP_Initialize"); 186 m_NPP_Shutdown = (NPP_ShutdownProcPtr)m_module->resolve("NP_Shutdown"); 187 188 if (!NP_Initialize || !m_NPP_Shutdown) 189 goto abort; 190 191 memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); 192 m_pluginFuncs.size = sizeof(m_pluginFuncs); 193 194 initializeBrowserFuncs(); 195 196 if (m_path.contains("npwrapper.") || m_path.contains("gnash")) { 197 // nspluginwrapper relies on the toolkit value to know if glib is available 198 // It does so in NP_Initialize with a null instance, therefore it is done this way: 199 m_browserFuncs.getvalue = staticPluginQuirkRequiresGtkToolKit_NPN_GetValue; 200 // Workaround Adobe's failure to properly initialize Gtk in some versions 201 // of their flash player plugin. 202 initializeGtk(); 203 } else if (m_path.contains("flashplayer")) { 204 // Workaround Adobe's failure to properly initialize Gtk in some versions 205 // of their flash player plugin. 206 initializeGtk(m_module); 207 } 208 209#if defined(XP_UNIX) 210 npErr = NP_Initialize(&m_browserFuncs, &m_pluginFuncs); 211#else 212 npErr = NP_Initialize(&m_browserFuncs); 213#endif 214 if (npErr != NPERR_NO_ERROR) 215 goto abort; 216 217 m_loadCount++; 218 return true; 219 220abort: 221 unloadWithoutShutdown(); 222 return false; 223} 224 225uint16_t PluginPackage::NPVersion() const 226{ 227 return NP_VERSION_MINOR; 228} 229 230} 231