/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPluginTags.h" #include "prlink.h" #include "plstr.h" #include "nsIPluginInstanceOwner.h" #include "nsPluginsDir.h" #include "nsPluginHost.h" #include "nsIBlocklistService.h" #include "nsIUnicodeDecoder.h" #include "nsIPlatformCharset.h" #include "nsPluginLogging.h" #include "nsNPAPIPlugin.h" #include "nsCharSeparatedTokenizer.h" #include "mozilla/Preferences.h" #include "mozilla/Unused.h" #include "nsNetUtil.h" #include #include "mozilla/dom/EncodingUtils.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/FakePluginTagInitBinding.h" using mozilla::dom::EncodingUtils; using mozilla::dom::FakePluginTagInit; using namespace mozilla; // These legacy flags are used in the plugin registry. The states are now // stored in prefs, but we still need to be able to import them. #define NS_PLUGIN_FLAG_ENABLED 0x0001 // is this plugin enabled? // no longer used 0x0002 // reuse only if regenerating pluginreg.dat #define NS_PLUGIN_FLAG_FROMCACHE 0x0004 // this plugintag info was loaded from cache // no longer used 0x0008 // reuse only if regenerating pluginreg.dat #define NS_PLUGIN_FLAG_CLICKTOPLAY 0x0020 // this is a click-to-play plugin static const char kPrefDefaultEnabledState[] = "plugin.default.state"; static const char kPrefDefaultEnabledStateXpi[] = "plugin.defaultXpi.state"; // check comma delimited extensions static bool ExtensionInList(const nsCString& aExtensionList, const nsACString& aExtension) { nsCCharSeparatedTokenizer extensions(aExtensionList, ','); while (extensions.hasMoreTokens()) { const nsCSubstring& extension = extensions.nextToken(); if (extension.Equals(aExtension, nsCaseInsensitiveCStringComparator())) { return true; } } return false; } // Search for an extension in an extensions array, and return its // matching mime type static bool SearchExtensions(const nsTArray & aExtensions, const nsTArray & aMimeTypes, const nsACString & aFindExtension, nsACString & aMatchingType) { uint32_t mimes = aMimeTypes.Length(); MOZ_ASSERT(mimes == aExtensions.Length(), "These arrays should have matching elements"); aMatchingType.Truncate(); for (uint32_t i = 0; i < mimes; i++) { if (ExtensionInList(aExtensions[i], aFindExtension)) { aMatchingType = aMimeTypes[i]; return true; } } return false; } static nsCString MakeNiceFileName(const nsCString & aFileName) { nsCString niceName = aFileName; int32_t niceNameLength = aFileName.RFind("."); NS_ASSERTION(niceNameLength != kNotFound, "aFileName doesn't have a '.'?"); while (niceNameLength > 0) { char chr = aFileName[niceNameLength - 1]; if (!std::isalpha(chr)) niceNameLength--; else break; } // If it turns out that niceNameLength <= 0, we'll fall back and use the // entire aFileName (which we've already taken care of, a few lines back). if (niceNameLength > 0) { niceName.Truncate(niceNameLength); } ToLowerCase(niceName); return niceName; } static nsCString MakePrefNameForPlugin(const char* const subname, nsIInternalPluginTag* aTag) { nsCString pref; nsAutoCString pluginName(aTag->GetNiceFileName()); if (pluginName.IsEmpty()) { // Use filename if nice name fails pluginName = aTag->FileName(); if (pluginName.IsEmpty()) { MOZ_ASSERT_UNREACHABLE("Plugin with no filename or nice name in list"); pluginName.AssignLiteral("unknown-plugin-name"); } } pref.AssignLiteral("plugin."); pref.Append(subname); pref.Append('.'); pref.Append(pluginName); return pref; } static nsresult CStringArrayToXPCArray(nsTArray & aArray, uint32_t* aCount, char16_t*** aResults) { uint32_t count = aArray.Length(); if (!count) { *aResults = nullptr; *aCount = 0; return NS_OK; } *aResults = static_cast(moz_xmalloc(count * sizeof(**aResults))); *aCount = count; for (uint32_t i = 0; i < count; i++) { (*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(aArray[i])); } return NS_OK; } static nsCString GetStatePrefNameForPlugin(nsIInternalPluginTag* aTag) { return MakePrefNameForPlugin("state", aTag); } static nsresult IsEnabledStateLockedForPlugin(nsIInternalPluginTag* aTag, bool* aIsEnabledStateLocked) { *aIsEnabledStateLocked = false; nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); if (NS_WARN_IF(!prefs)) { return NS_ERROR_FAILURE; } Unused << prefs->PrefIsLocked(GetStatePrefNameForPlugin(aTag).get(), aIsEnabledStateLocked); return NS_OK; } /* nsIInternalPluginTag */ nsIInternalPluginTag::nsIInternalPluginTag() { } nsIInternalPluginTag::nsIInternalPluginTag(const char* aName, const char* aDescription, const char* aFileName, const char* aVersion) : mName(aName) , mDescription(aDescription) , mFileName(aFileName) , mVersion(aVersion) { } nsIInternalPluginTag::nsIInternalPluginTag(const char* aName, const char* aDescription, const char* aFileName, const char* aVersion, const nsTArray& aMimeTypes, const nsTArray& aMimeDescriptions, const nsTArray& aExtensions) : mName(aName) , mDescription(aDescription) , mFileName(aFileName) , mVersion(aVersion) , mMimeTypes(aMimeTypes) , mMimeDescriptions(aMimeDescriptions) , mExtensions(aExtensions) { } nsIInternalPluginTag::~nsIInternalPluginTag() { } bool nsIInternalPluginTag::HasExtension(const nsACString& aExtension, nsACString& aMatchingType) const { return SearchExtensions(mExtensions, mMimeTypes, aExtension, aMatchingType); } bool nsIInternalPluginTag::HasMimeType(const nsACString& aMimeType) const { return mMimeTypes.Contains(aMimeType, nsCaseInsensitiveCStringArrayComparator()); } /* nsPluginTag */ uint32_t nsPluginTag::sNextId; nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo, int64_t aLastModifiedTime, bool fromExtension) : nsIInternalPluginTag(aPluginInfo->fName, aPluginInfo->fDescription, aPluginInfo->fFileName, aPluginInfo->fVersion), mId(sNextId++), mContentProcessRunningCount(0), mHadLocalInstance(false), mLibrary(nullptr), mIsJavaPlugin(false), mIsFlashPlugin(false), mSupportsAsyncInit(false), mSupportsAsyncRender(false), mFullPath(aPluginInfo->fFullPath), mLastModifiedTime(aLastModifiedTime), mSandboxLevel(0), mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED), mCachedBlocklistStateValid(false), mIsFromExtension(fromExtension) { InitMime(aPluginInfo->fMimeTypeArray, aPluginInfo->fMimeDescriptionArray, aPluginInfo->fExtensionArray, aPluginInfo->fVariantCount); EnsureMembersAreUTF8(); FixupVersion(); } nsPluginTag::nsPluginTag(const char* aName, const char* aDescription, const char* aFileName, const char* aFullPath, const char* aVersion, const char* const* aMimeTypes, const char* const* aMimeDescriptions, const char* const* aExtensions, int32_t aVariants, int64_t aLastModifiedTime, bool fromExtension, bool aArgsAreUTF8) : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion), mId(sNextId++), mContentProcessRunningCount(0), mHadLocalInstance(false), mLibrary(nullptr), mIsJavaPlugin(false), mIsFlashPlugin(false), mSupportsAsyncInit(false), mSupportsAsyncRender(false), mFullPath(aFullPath), mLastModifiedTime(aLastModifiedTime), mSandboxLevel(0), mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED), mCachedBlocklistStateValid(false), mIsFromExtension(fromExtension) { InitMime(aMimeTypes, aMimeDescriptions, aExtensions, static_cast(aVariants)); if (!aArgsAreUTF8) EnsureMembersAreUTF8(); FixupVersion(); } nsPluginTag::nsPluginTag(uint32_t aId, const char* aName, const char* aDescription, const char* aFileName, const char* aFullPath, const char* aVersion, nsTArray aMimeTypes, nsTArray aMimeDescriptions, nsTArray aExtensions, bool aIsJavaPlugin, bool aIsFlashPlugin, bool aSupportsAsyncInit, bool aSupportsAsyncRender, int64_t aLastModifiedTime, bool aFromExtension, int32_t aSandboxLevel) : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion, aMimeTypes, aMimeDescriptions, aExtensions), mId(aId), mContentProcessRunningCount(0), mLibrary(nullptr), mIsJavaPlugin(aIsJavaPlugin), mIsFlashPlugin(aIsFlashPlugin), mSupportsAsyncInit(aSupportsAsyncInit), mSupportsAsyncRender(aSupportsAsyncRender), mLastModifiedTime(aLastModifiedTime), mSandboxLevel(aSandboxLevel), mNiceFileName(), mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED), mCachedBlocklistStateValid(false), mIsFromExtension(aFromExtension) { } nsPluginTag::~nsPluginTag() { NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349"); } NS_IMPL_ISUPPORTS(nsPluginTag, nsPluginTag, nsIInternalPluginTag, nsIPluginTag) void nsPluginTag::InitMime(const char* const* aMimeTypes, const char* const* aMimeDescriptions, const char* const* aExtensions, uint32_t aVariantCount) { if (!aMimeTypes) { return; } for (uint32_t i = 0; i < aVariantCount; i++) { if (!aMimeTypes[i]) { continue; } nsAutoCString mimeType(aMimeTypes[i]); // Convert the MIME type, which is case insensitive, to lowercase in order // to properly handle a mixed-case type. ToLowerCase(mimeType); if (!nsPluginHost::IsTypeWhitelisted(mimeType.get())) { continue; } // Look for certain special plugins. switch (nsPluginHost::GetSpecialType(mimeType)) { case nsPluginHost::eSpecialType_Java: mIsJavaPlugin = true; mSupportsAsyncInit = true; break; case nsPluginHost::eSpecialType_Flash: // VLC sometimes claims to implement the Flash MIME type, and we want // to allow users to control that separately from Adobe Flash. if (Name().EqualsLiteral("Shockwave Flash")) { mIsFlashPlugin = true; mSupportsAsyncInit = true; } break; case nsPluginHost::eSpecialType_Silverlight: case nsPluginHost::eSpecialType_Unity: case nsPluginHost::eSpecialType_Test: mSupportsAsyncInit = true; break; case nsPluginHost::eSpecialType_None: default: #ifndef RELEASE_OR_BETA // Allow async init for all plugins on Nightly and Aurora mSupportsAsyncInit = true; #endif break; } // Fill in our MIME type array. mMimeTypes.AppendElement(mimeType); // Now fill in the MIME descriptions. if (aMimeDescriptions && aMimeDescriptions[i]) { // we should cut off the list of suffixes which the mime // description string may have, see bug 53895 // it is usually in form "some description (*.sf1, *.sf2)" // so we can search for the opening round bracket char cur = '\0'; char pre = '\0'; char * p = PL_strrchr(aMimeDescriptions[i], '('); if (p && (p != aMimeDescriptions[i])) { if ((p - 1) && *(p - 1) == ' ') { pre = *(p - 1); *(p - 1) = '\0'; } else { cur = *p; *p = '\0'; } } mMimeDescriptions.AppendElement(nsCString(aMimeDescriptions[i])); // restore the original string if (cur != '\0') { *p = cur; } if (pre != '\0') { *(p - 1) = pre; } } else { mMimeDescriptions.AppendElement(nsCString()); } // Now fill in the extensions. if (aExtensions && aExtensions[i]) { mExtensions.AppendElement(nsCString(aExtensions[i])); } else { mExtensions.AppendElement(nsCString()); } } } #if !defined(XP_WIN) && !defined(XP_MACOSX) static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder, nsAFlatCString& aString) { int32_t numberOfBytes = aString.Length(); int32_t outUnicodeLen; nsAutoString buffer; nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes, &outUnicodeLen); NS_ENSURE_SUCCESS(rv, rv); if (!buffer.SetLength(outUnicodeLen, fallible)) return NS_ERROR_OUT_OF_MEMORY; rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes, buffer.BeginWriting(), &outUnicodeLen); NS_ENSURE_SUCCESS(rv, rv); buffer.SetLength(outUnicodeLen); CopyUTF16toUTF8(buffer, aString); return NS_OK; } #endif nsresult nsPluginTag::EnsureMembersAreUTF8() { #if defined(XP_WIN) || defined(XP_MACOSX) return NS_OK; #else nsresult rv; nsCOMPtr pcs = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr decoder; nsAutoCString charset; rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset); NS_ENSURE_SUCCESS(rv, rv); if (!charset.LowerCaseEqualsLiteral("utf-8")) { decoder = EncodingUtils::DecoderForEncoding(charset); ConvertToUTF8(decoder, mFileName); ConvertToUTF8(decoder, mFullPath); } // The description of the plug-in and the various MIME type descriptions // should be encoded in the standard plain text file encoding for this system. // XXX should we add kPlatformCharsetSel_PluginResource? rv = pcs->GetCharset(kPlatformCharsetSel_PlainTextInFile, charset); NS_ENSURE_SUCCESS(rv, rv); if (!charset.LowerCaseEqualsLiteral("utf-8")) { decoder = EncodingUtils::DecoderForEncoding(charset); ConvertToUTF8(decoder, mName); ConvertToUTF8(decoder, mDescription); for (uint32_t i = 0; i < mMimeDescriptions.Length(); ++i) { ConvertToUTF8(decoder, mMimeDescriptions[i]); } } return NS_OK; #endif } void nsPluginTag::FixupVersion() { #if defined(XP_LINUX) if (mIsFlashPlugin) { mVersion.ReplaceChar(',', '.'); } #endif } NS_IMETHODIMP nsPluginTag::GetDescription(nsACString& aDescription) { aDescription = mDescription; return NS_OK; } NS_IMETHODIMP nsPluginTag::GetFilename(nsACString& aFileName) { aFileName = mFileName; return NS_OK; } NS_IMETHODIMP nsPluginTag::GetFullpath(nsACString& aFullPath) { aFullPath = mFullPath; return NS_OK; } NS_IMETHODIMP nsPluginTag::GetVersion(nsACString& aVersion) { aVersion = mVersion; return NS_OK; } NS_IMETHODIMP nsPluginTag::GetName(nsACString& aName) { aName = mName; return NS_OK; } bool nsPluginTag::IsActive() { return IsEnabled() && !IsBlocklisted(); } NS_IMETHODIMP nsPluginTag::GetActive(bool *aResult) { *aResult = IsActive(); return NS_OK; } bool nsPluginTag::IsEnabled() { const PluginState state = GetPluginState(); return (state == ePluginState_Enabled) || (state == ePluginState_Clicktoplay); } NS_IMETHODIMP nsPluginTag::GetDisabled(bool* aDisabled) { *aDisabled = !IsEnabled(); return NS_OK; } bool nsPluginTag::IsBlocklisted() { uint32_t blocklistState; nsresult rv = GetBlocklistState(&blocklistState); return NS_FAILED(rv) || blocklistState == nsIBlocklistService::STATE_BLOCKED; } NS_IMETHODIMP nsPluginTag::GetBlocklisted(bool* aBlocklisted) { *aBlocklisted = IsBlocklisted(); return NS_OK; } NS_IMETHODIMP nsPluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked) { return IsEnabledStateLockedForPlugin(this, aIsEnabledStateLocked); } bool nsPluginTag::IsClicktoplay() { const PluginState state = GetPluginState(); return (state == ePluginState_Clicktoplay); } NS_IMETHODIMP nsPluginTag::GetClicktoplay(bool *aClicktoplay) { *aClicktoplay = IsClicktoplay(); return NS_OK; } NS_IMETHODIMP nsPluginTag::GetEnabledState(uint32_t *aEnabledState) { int32_t enabledState; nsresult rv = Preferences::GetInt(GetStatePrefNameForPlugin(this).get(), &enabledState); if (NS_SUCCEEDED(rv) && enabledState >= nsIPluginTag::STATE_DISABLED && enabledState <= nsIPluginTag::STATE_ENABLED) { *aEnabledState = (uint32_t)enabledState; return rv; } const char* const pref = mIsFromExtension ? kPrefDefaultEnabledStateXpi : kPrefDefaultEnabledState; enabledState = Preferences::GetInt(pref, nsIPluginTag::STATE_ENABLED); if (enabledState >= nsIPluginTag::STATE_DISABLED && enabledState <= nsIPluginTag::STATE_ENABLED) { *aEnabledState = (uint32_t)enabledState; return NS_OK; } return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP nsPluginTag::SetEnabledState(uint32_t aEnabledState) { if (aEnabledState >= ePluginState_MaxValue) return NS_ERROR_ILLEGAL_VALUE; uint32_t oldState = nsIPluginTag::STATE_DISABLED; GetEnabledState(&oldState); if (oldState != aEnabledState) { Preferences::SetInt(GetStatePrefNameForPlugin(this).get(), aEnabledState); if (RefPtr host = nsPluginHost::GetInst()) { host->UpdatePluginInfo(this); } } return NS_OK; } nsPluginTag::PluginState nsPluginTag::GetPluginState() { uint32_t enabledState = nsIPluginTag::STATE_DISABLED; GetEnabledState(&enabledState); return (PluginState)enabledState; } void nsPluginTag::SetPluginState(PluginState state) { static_assert((uint32_t)nsPluginTag::ePluginState_Disabled == nsIPluginTag::STATE_DISABLED, "nsPluginTag::ePluginState_Disabled must match nsIPluginTag::STATE_DISABLED"); static_assert((uint32_t)nsPluginTag::ePluginState_Clicktoplay == nsIPluginTag::STATE_CLICKTOPLAY, "nsPluginTag::ePluginState_Clicktoplay must match nsIPluginTag::STATE_CLICKTOPLAY"); static_assert((uint32_t)nsPluginTag::ePluginState_Enabled == nsIPluginTag::STATE_ENABLED, "nsPluginTag::ePluginState_Enabled must match nsIPluginTag::STATE_ENABLED"); SetEnabledState((uint32_t)state); } NS_IMETHODIMP nsPluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults) { return CStringArrayToXPCArray(mMimeTypes, aCount, aResults); } NS_IMETHODIMP nsPluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults) { return CStringArrayToXPCArray(mMimeDescriptions, aCount, aResults); } NS_IMETHODIMP nsPluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults) { return CStringArrayToXPCArray(mExtensions, aCount, aResults); } bool nsPluginTag::HasSameNameAndMimes(const nsPluginTag *aPluginTag) const { NS_ENSURE_TRUE(aPluginTag, false); if ((!mName.Equals(aPluginTag->mName)) || (mMimeTypes.Length() != aPluginTag->mMimeTypes.Length())) { return false; } for (uint32_t i = 0; i < mMimeTypes.Length(); i++) { if (!mMimeTypes[i].Equals(aPluginTag->mMimeTypes[i])) { return false; } } return true; } NS_IMETHODIMP nsPluginTag::GetLoaded(bool* aIsLoaded) { *aIsLoaded = !!mPlugin; return NS_OK; } void nsPluginTag::TryUnloadPlugin(bool inShutdown) { // We never want to send NPP_Shutdown to an in-process plugin unless // this process is shutting down. if (!mPlugin) { return; } if (inShutdown || mPlugin->GetLibrary()->IsOOP()) { mPlugin->Shutdown(); mPlugin = nullptr; } } const nsCString& nsPluginTag::GetNiceFileName() { if (!mNiceFileName.IsEmpty()) { return mNiceFileName; } if (mIsFlashPlugin) { mNiceFileName.AssignLiteral("flash"); return mNiceFileName; } if (mIsJavaPlugin) { mNiceFileName.AssignLiteral("java"); return mNiceFileName; } mNiceFileName = MakeNiceFileName(mFileName); return mNiceFileName; } NS_IMETHODIMP nsPluginTag::GetNiceName(nsACString & aResult) { aResult = GetNiceFileName(); return NS_OK; } NS_IMETHODIMP nsPluginTag::GetBlocklistState(uint32_t *aResult) { if (mCachedBlocklistStateValid) { *aResult = mCachedBlocklistState; return NS_OK; } if (!XRE_IsParentProcess()) { *aResult = nsIBlocklistService::STATE_BLOCKED; dom::ContentChild* cp = dom::ContentChild::GetSingleton(); if (!cp->SendGetBlocklistState(mId, aResult)) { return NS_OK; } } else { nsCOMPtr blocklist = do_GetService("@mozilla.org/extensions/blocklist;1"); if (!blocklist) { *aResult = nsIBlocklistService::STATE_NOT_BLOCKED; return NS_OK; } // The EmptyString()s are so we use the currently running application // and toolkit versions if (NS_FAILED(blocklist->GetPluginBlocklistState(this, EmptyString(), EmptyString(), aResult))) { *aResult = nsIBlocklistService::STATE_NOT_BLOCKED; return NS_OK; } } MOZ_ASSERT(*aResult <= UINT16_MAX); mCachedBlocklistState = (uint16_t) *aResult; mCachedBlocklistStateValid = true; return NS_OK; } void nsPluginTag::InvalidateBlocklistState() { mCachedBlocklistStateValid = false; } NS_IMETHODIMP nsPluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime) { MOZ_ASSERT(aLastModifiedTime); *aLastModifiedTime = mLastModifiedTime; return NS_OK; } bool nsPluginTag::IsFromExtension() const { return mIsFromExtension; } /* nsFakePluginTag */ nsFakePluginTag::nsFakePluginTag() : mState(nsPluginTag::ePluginState_Disabled) { } nsFakePluginTag::~nsFakePluginTag() { } NS_IMPL_ADDREF(nsFakePluginTag) NS_IMPL_RELEASE(nsFakePluginTag) NS_INTERFACE_TABLE_HEAD(nsFakePluginTag) NS_INTERFACE_TABLE_BEGIN NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsFakePluginTag, nsIPluginTag, nsIInternalPluginTag) NS_INTERFACE_TABLE_ENTRY(nsFakePluginTag, nsIInternalPluginTag) NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsFakePluginTag, nsISupports, nsIInternalPluginTag) NS_INTERFACE_TABLE_ENTRY(nsFakePluginTag, nsIFakePluginTag) NS_INTERFACE_TABLE_END NS_INTERFACE_TABLE_TAIL /* static */ nsresult nsFakePluginTag::Create(const FakePluginTagInit& aInitDictionary, nsFakePluginTag** aPluginTag) { NS_ENSURE_TRUE(!aInitDictionary.mMimeEntries.IsEmpty(), NS_ERROR_INVALID_ARG); RefPtr tag = new nsFakePluginTag(); nsresult rv = NS_NewURI(getter_AddRefs(tag->mHandlerURI), aInitDictionary.mHandlerURI); NS_ENSURE_SUCCESS(rv, rv); CopyUTF16toUTF8(aInitDictionary.mNiceName, tag->mNiceName); CopyUTF16toUTF8(aInitDictionary.mFullPath, tag->mFullPath); CopyUTF16toUTF8(aInitDictionary.mName, tag->mName); CopyUTF16toUTF8(aInitDictionary.mDescription, tag->mDescription); CopyUTF16toUTF8(aInitDictionary.mFileName, tag->mFileName); CopyUTF16toUTF8(aInitDictionary.mVersion, tag->mVersion); for (const FakePluginMimeEntry& mimeEntry : aInitDictionary.mMimeEntries) { CopyUTF16toUTF8(mimeEntry.mType, *tag->mMimeTypes.AppendElement()); CopyUTF16toUTF8(mimeEntry.mDescription, *tag->mMimeDescriptions.AppendElement()); CopyUTF16toUTF8(mimeEntry.mExtension, *tag->mExtensions.AppendElement()); } tag.forget(aPluginTag); return NS_OK; } bool nsFakePluginTag::HandlerURIMatches(nsIURI* aURI) { bool equals = false; return NS_SUCCEEDED(mHandlerURI->Equals(aURI, &equals)) && equals; } NS_IMETHODIMP nsFakePluginTag::GetHandlerURI(nsIURI **aResult) { NS_IF_ADDREF(*aResult = mHandlerURI); return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetDescription(/* utf-8 */ nsACString& aResult) { aResult = mDescription; return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetFilename(/* utf-8 */ nsACString& aResult) { aResult = mFileName; return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetFullpath(/* utf-8 */ nsACString& aResult) { aResult = mFullPath; return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetVersion(/* utf-8 */ nsACString& aResult) { aResult = mVersion; return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetName(/* utf-8 */ nsACString& aResult) { aResult = mName; return NS_OK; } const nsCString& nsFakePluginTag::GetNiceFileName() { // We don't try to mimic the special-cased flash/java names if the fake plugin // claims one of their MIME types, but do allow directly setting niceName if // emulating those is desired. if (mNiceName.IsEmpty() && !mFileName.IsEmpty()) { mNiceName = MakeNiceFileName(mFileName); } return mNiceName; } NS_IMETHODIMP nsFakePluginTag::GetNiceName(/* utf-8 */ nsACString& aResult) { aResult = GetNiceFileName(); return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetBlocklistState(uint32_t* aResult) { // Fake tags don't currently support blocklisting *aResult = nsIBlocklistService::STATE_NOT_BLOCKED; return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetBlocklisted(bool* aBlocklisted) { // Fake tags can't be blocklisted *aBlocklisted = false; return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked) { return IsEnabledStateLockedForPlugin(this, aIsEnabledStateLocked); } bool nsFakePluginTag::IsEnabled() { return mState == nsPluginTag::ePluginState_Enabled || mState == nsPluginTag::ePluginState_Clicktoplay; } NS_IMETHODIMP nsFakePluginTag::GetDisabled(bool* aDisabled) { *aDisabled = !IsEnabled(); return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetClicktoplay(bool* aClicktoplay) { *aClicktoplay = (mState == nsPluginTag::ePluginState_Clicktoplay); return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetEnabledState(uint32_t* aEnabledState) { *aEnabledState = (uint32_t)mState; return NS_OK; } NS_IMETHODIMP nsFakePluginTag::SetEnabledState(uint32_t aEnabledState) { // There are static asserts above enforcing that this enum matches mState = (nsPluginTag::PluginState)aEnabledState; // FIXME-jsplugins update return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults) { return CStringArrayToXPCArray(mMimeTypes, aCount, aResults); } NS_IMETHODIMP nsFakePluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults) { return CStringArrayToXPCArray(mMimeDescriptions, aCount, aResults); } NS_IMETHODIMP nsFakePluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults) { return CStringArrayToXPCArray(mExtensions, aCount, aResults); } NS_IMETHODIMP nsFakePluginTag::GetActive(bool *aResult) { // Fake plugins can't be blocklisted, so this is just !Disabled *aResult = IsEnabled(); return NS_OK; } NS_IMETHODIMP nsFakePluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime) { // FIXME-jsplugins What should this return, if anything? MOZ_ASSERT(aLastModifiedTime); *aLastModifiedTime = 0; return NS_OK; } // We don't load fake plugins out of a library, so they should always be there. NS_IMETHODIMP nsFakePluginTag::GetLoaded(bool* ret) { *ret = true; return NS_OK; }