2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "PluginPackageWin.h"
32 #include "DeprecatedString.h"
33 #include "npruntime_impl.h"
34 #include "PluginDebug.h"
38 PluginPackageWin::~PluginPackageWin()
43 static String getVersionInfo(const LPVOID versionInfoData, const String& info)
47 String subInfo = "\\StringfileInfo\\040904E4\\" + info;
49 bool retval = VerQueryValueW(versionInfoData, const_cast<UChar*>(subInfo.charactersWithNullTermination()),
50 &buffer, &bufferLength);
51 if (!retval || bufferLength == 0)
54 // Subtract 1 from the length; we don't want the trailing 0
55 return String(reinterpret_cast<UChar*>(buffer), bufferLength - 1);
58 static Vector<String> splitString(const String& str, char delimiter, int padTo)
62 Vector<String> result;
63 DeprecatedString ds = str.deprecatedString();
67 newPos = ds.find(delimiter, pos);
72 s = ds.mid(pos, newPos - pos);
78 } while (newPos != -1);
80 while (padTo != -1 && static_cast<int>(result.size()) < padTo)
86 void PluginPackageWin::freeLibrarySoon()
88 ASSERT(!m_freeLibraryTimer.isActive());
90 ASSERT(m_loadCount == 0);
92 m_freeLibraryTimer.startOneShot(0);
95 void PluginPackageWin::freeLibraryTimerFired(Timer<PluginPackageWin>* /*timer*/)
98 ASSERT(m_loadCount == 0);
100 ::FreeLibrary(m_module);
104 PluginPackageWin::PluginPackageWin(const String& path, const FILETIME& lastModified)
107 , m_lastModified(lastModified)
110 , m_freeLibraryTimer(this, &PluginPackageWin::freeLibraryTimerFired)
114 m_fileName = String(PathFindFileName(m_path.charactersWithNullTermination()));
115 m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1);
118 int PluginPackageWin::compareFileVersion(unsigned compareVersionMS, unsigned compareVersionLS) const
120 // return -1, 0, or 1 if plug-in version is less than, equal to, or greater than
121 // the passed version
122 if (m_fileVersionMS != compareVersionMS)
123 return m_fileVersionMS > compareVersionMS ? 1 : -1;
124 if (m_fileVersionLS != compareVersionLS)
125 return m_fileVersionLS > compareVersionLS ? 1 : -1;
129 void PluginPackageWin::storeFileVersion(LPVOID versionInfoData)
131 VS_FIXEDFILEINFO* info;
133 if (!VerQueryValue(versionInfoData, TEXT("\\"), (LPVOID*) &info, &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO))
135 m_fileVersionLS = info->dwFileVersionLS;
136 m_fileVersionMS = info->dwFileVersionMS;
139 bool PluginPackageWin::isPluginBlacklisted()
141 static const unsigned silverlightPluginMinRequiredVersionMS = 0x00010000;
142 static const unsigned silverlightPluginMinRequiredVersionLS = 0x51BE0000;
144 if (name() == "Silverlight Plug-In") {
145 // workaround for <rdar://5557379> Crash in Silverlight when opening microsoft.com.
146 // the latest 1.0 version of Silverlight does not reproduce this crash, so allow it
147 // and any newer versions
148 if (compareFileVersion(silverlightPluginMinRequiredVersionMS, silverlightPluginMinRequiredVersionLS) < 0)
150 } else if (fileName() == "npmozax.dll")
151 // Bug 15217: Mozilla ActiveX control complains about missing xpcom_core.dll
157 bool PluginPackageWin::fetchInfo()
159 DWORD versionInfoSize, zeroHandle;
160 versionInfoSize = GetFileVersionInfoSizeW(m_path.charactersWithNullTermination(), &zeroHandle);
162 if (versionInfoSize == 0)
165 LPVOID versionInfoData = fastMalloc(versionInfoSize);
167 if (!GetFileVersionInfoW(m_path.charactersWithNullTermination(), 0, versionInfoSize, versionInfoData)) {
168 fastFree(versionInfoData);
172 m_name = getVersionInfo(versionInfoData, "ProductName");
173 m_description = getVersionInfo(versionInfoData, "FileDescription");
175 if (m_name.isNull() || m_description.isNull()) {
176 fastFree(versionInfoData);
180 storeFileVersion(versionInfoData);
182 if (isPluginBlacklisted()) {
183 fastFree(versionInfoData);
187 Vector<String> mimeTypes = splitString(getVersionInfo(versionInfoData, "MIMEType"), '|', -1);
188 Vector<String> fileExtents = splitString(getVersionInfo(versionInfoData, "FileExtents"), '|', mimeTypes.size());
189 Vector<String> descriptions = splitString(getVersionInfo(versionInfoData, "FileOpenName"), '|', mimeTypes.size());
191 fastFree(versionInfoData);
193 for (unsigned i = 0; i < mimeTypes.size(); i++) {
194 // Get rid of the extension list in the description string
195 String description = descriptions[i];
196 int pos = description.find("(*");
198 // There might be a space that we need to get rid of
199 if (pos > 1 && description[pos - 1] == ' ')
202 description = description.left(pos);
205 mimeTypes[i] = mimeTypes[i].lower();
207 m_mimeToExtensions.add(mimeTypes[i], splitString(fileExtents[i], ',', -1));
208 m_mimeToDescriptions.add(mimeTypes[i], description);
214 bool PluginPackageWin::load()
216 if (m_freeLibraryTimer.isActive()) {
218 m_freeLibraryTimer.stop();
219 } else if (m_isLoaded) {
223 WCHAR currentPath[MAX_PATH];
225 if (!::GetCurrentDirectoryW(MAX_PATH, currentPath))
228 String path = m_path.substring(0, m_path.reverseFind('\\'));
230 if (!::SetCurrentDirectoryW(path.charactersWithNullTermination()))
234 m_module = ::LoadLibraryW(m_path.charactersWithNullTermination());
236 if (!::SetCurrentDirectoryW(currentPath)) {
238 ::FreeLibrary(m_module);
248 NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0;
249 NP_InitializeFuncPtr NP_Initialize = 0;
252 NP_Initialize = (NP_InitializeFuncPtr)GetProcAddress(m_module, "NP_Initialize");
253 NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)GetProcAddress(m_module, "NP_GetEntryPoints");
254 m_NPP_Shutdown = (NPP_ShutdownProcPtr)GetProcAddress(m_module, "NP_Shutdown");
256 if (!NP_Initialize || !NP_GetEntryPoints || !m_NPP_Shutdown)
259 memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
260 m_pluginFuncs.size = sizeof(m_pluginFuncs);
262 npErr = NP_GetEntryPoints(&m_pluginFuncs);
264 if (npErr != NPERR_NO_ERROR)
267 memset(&m_browserFuncs, 0, sizeof(m_browserFuncs));
268 m_browserFuncs.size = sizeof (m_browserFuncs);
269 m_browserFuncs.version = NP_VERSION_MINOR;
270 m_browserFuncs.geturl = NPN_GetURL;
271 m_browserFuncs.posturl = NPN_PostURL;
272 m_browserFuncs.requestread = NPN_RequestRead;
273 m_browserFuncs.newstream = NPN_NewStream;
274 m_browserFuncs.write = NPN_Write;
275 m_browserFuncs.destroystream = NPN_DestroyStream;
276 m_browserFuncs.status = NPN_Status;
277 m_browserFuncs.uagent = NPN_UserAgent;
278 m_browserFuncs.memalloc = NPN_MemAlloc;
279 m_browserFuncs.memfree = NPN_MemFree;
280 m_browserFuncs.memflush = NPN_MemFlush;
281 m_browserFuncs.reloadplugins = NPN_ReloadPlugins;
282 m_browserFuncs.geturlnotify = NPN_GetURLNotify;
283 m_browserFuncs.posturlnotify = NPN_PostURLNotify;
284 m_browserFuncs.getvalue = NPN_GetValue;
285 m_browserFuncs.setvalue = NPN_SetValue;
286 m_browserFuncs.invalidaterect = NPN_InvalidateRect;
287 m_browserFuncs.invalidateregion = NPN_InvalidateRegion;
288 m_browserFuncs.forceredraw = NPN_ForceRedraw;
289 m_browserFuncs.getJavaEnv = NPN_GetJavaEnv;
290 m_browserFuncs.getJavaPeer = NPN_GetJavaPeer;
291 m_browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
292 m_browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
294 m_browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue;
295 m_browserFuncs.getstringidentifier = _NPN_GetStringIdentifier;
296 m_browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers;
297 m_browserFuncs.getintidentifier = _NPN_GetIntIdentifier;
298 m_browserFuncs.identifierisstring = _NPN_IdentifierIsString;
299 m_browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier;
300 m_browserFuncs.intfromidentifier = _NPN_IntFromIdentifier;
301 m_browserFuncs.createobject = _NPN_CreateObject;
302 m_browserFuncs.retainobject = _NPN_RetainObject;
303 m_browserFuncs.releaseobject = _NPN_ReleaseObject;
304 m_browserFuncs.invoke = _NPN_Invoke;
305 m_browserFuncs.invokeDefault = _NPN_InvokeDefault;
306 m_browserFuncs.evaluate = _NPN_Evaluate;
307 m_browserFuncs.getproperty = _NPN_GetProperty;
308 m_browserFuncs.setproperty = _NPN_SetProperty;
309 m_browserFuncs.removeproperty = _NPN_RemoveProperty;
310 m_browserFuncs.hasproperty = _NPN_HasProperty;
311 m_browserFuncs.hasmethod = _NPN_HasMethod;
312 m_browserFuncs.setexception = _NPN_SetException;
313 m_browserFuncs.enumerate = _NPN_Enumerate;
315 npErr = NP_Initialize(&m_browserFuncs);
318 if (npErr != NPERR_NO_ERROR)
324 unloadWithoutShutdown();
328 void PluginPackageWin::unload()
333 if (--m_loadCount > 0)
338 unloadWithoutShutdown();
341 void PluginPackageWin::unloadWithoutShutdown()
346 ASSERT(m_loadCount == 0);
349 // <rdar://5530519>: Crash when closing tab with pdf file (Reader 7 only)
350 // If the plugin has subclassed its parent window, as with Reader 7, we may have
351 // gotten here by way of the plugin's internal window proc forwarding a message to our
352 // original window proc. If we free the plugin library from here, we will jump back
353 // to code we just freed when we return, so delay calling FreeLibrary at least until
354 // the next message loop
360 PluginPackageWin* PluginPackageWin::createPackage(const String& path, const FILETIME& lastModified)
362 PluginPackageWin* package = new PluginPackageWin(path, lastModified);
364 if (!package->fetchInfo()) {
372 unsigned PluginPackageWin::hash() const
374 unsigned hashCodes[3] = {
375 m_description.impl()->hash(),
376 m_lastModified.dwLowDateTime,
377 m_lastModified.dwHighDateTime
380 return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 3 * sizeof(unsigned) / sizeof(UChar));
383 bool PluginPackageWin::equal(const PluginPackageWin& a, const PluginPackageWin& b)
385 return a.m_description == b.m_description && (CompareFileTime(&a.m_lastModified, &b.m_lastModified) == 0);