예제 #1
0
String directoryName(const String& path)
{
    String fileName = pathGetFileName(path);
    String dirName = String(path);
    dirName.truncate(dirName.length() - pathGetFileName(path).length());
    return dirName;
}
void LocalStorageDatabaseTracker::updateTrackerDatabaseFromLocalStorageDatabaseFiles()
{
    Vector<String> paths = listDirectory(m_localStorageDirectory, "*.localstorage");

    HashSet<String> origins(m_origins);
    HashSet<String> originsFromLocalStorageDatabaseFiles;

    for (size_t i = 0; i < paths.size(); ++i) {
        const String& path = paths[i];

        if (!path.endsWith(".localstorage"))
            continue;

        String filename = pathGetFileName(path);

        String originIdentifier = filename.substring(0, filename.length() - strlen(".localstorage"));

        if (!m_origins.contains(originIdentifier))
            addDatabaseWithOriginIdentifier(originIdentifier, path);

        originsFromLocalStorageDatabaseFiles.add(originIdentifier);
    }

    for (auto it = origins.begin(), end = origins.end(); it != end; ++it) {
        const String& originIdentifier = *it;
        if (origins.contains(originIdentifier))
            continue;

        removeDatabaseWithOriginIdentifier(originIdentifier);
    }
}
File::File(const String& relativePath, const String& path)
    : Blob(createBlobDataForFile(path), -1)
    , m_path(path)
    , m_relativePath(relativePath)
{
    m_name = pathGetFileName(path);
}
bool NetscapePluginModule::getPluginInfo(const String& pluginPath, PluginInfoStore::Plugin& plugin)
{
        String pathCopy = pluginPath;
    DWORD versionInfoSize = ::GetFileVersionInfoSizeW(pathCopy.charactersWithNullTermination(), 0);
    if (!versionInfoSize)
        return false;

    OwnArrayPtr<char> versionInfoData = adoptArrayPtr(new char[versionInfoSize]);
    if (!::GetFileVersionInfoW(pathCopy.charactersWithNullTermination(), 0, versionInfoSize, versionInfoData.get()))
        return false;

    String name = getVersionInfo(versionInfoData.get(), "ProductName");
    String description = getVersionInfo(versionInfoData.get(), "FileDescription");
    if (name.isNull() || description.isNull())
        return false;

    VS_FIXEDFILEINFO* info;
    UINT infoSize;
    if (!::VerQueryValueW(versionInfoData.get(), L"\\", reinterpret_cast<void**>(&info), &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO))
        return false;

    Vector<String> types;
    getVersionInfo(versionInfoData.get(), "MIMEType").split('|', types);
    Vector<String> extensionLists;
    getVersionInfo(versionInfoData.get(), "FileExtents").split('|', extensionLists);
    Vector<String> descriptions;
    getVersionInfo(versionInfoData.get(), "FileOpenName").split('|', descriptions);

    Vector<MimeClassInfo> mimes(types.size());
    for (size_t i = 0; i < types.size(); i++) {
        String type = types[i].lower();
        String description = i < descriptions.size() ? descriptions[i] : "";
        String extensionList = i < extensionLists.size() ? extensionLists[i] : "";

        Vector<String> extensionsVector;
        extensionList.split(',', extensionsVector);

        // Get rid of the extension list that may be at the end of the description string.
        int pos = description.find("(*");
        if (pos != -1) {
            // There might be a space that we need to get rid of.
            if (pos > 1 && description[pos - 1] == ' ')
                pos--;
            description = description.left(pos);
        }

        mimes[i].type = type;
        mimes[i].desc = description;
        mimes[i].extensions.swap(extensionsVector);
    }

    plugin.path = pluginPath;
    plugin.info.desc = description;
    plugin.info.name = name;
    plugin.info.file = pathGetFileName(pluginPath);
    plugin.info.mimes.swap(mimes);
    plugin.fileVersion = fileVersion(info->dwFileVersionLS, info->dwFileVersionMS);

    return true;
}
예제 #5
0
bool NetscapePluginModule::getPluginInfoForLoadedPlugin(PluginModuleInfo& plugin)
{
    ASSERT(m_isInitialized);

    plugin.path = m_pluginPath;
    plugin.info.file = pathGetFileName(m_pluginPath);

    Module* module = m_module.get();
    NPP_GetValueProcPtr NPP_GetValue = module->functionPointer<NPP_GetValueProcPtr>("NP_GetValue");
    if (!NPP_GetValue)
        return false;

    NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription = module->functionPointer<NP_GetMIMEDescriptionFuncPtr>("NP_GetMIMEDescription");
    if (!NP_GetMIMEDescription)
        return false;

    char* buffer;
    NPError error = NPP_GetValue(0, NPPVpluginNameString, &buffer);
    if (error == NPERR_NO_ERROR)
        plugin.info.name = buffer;

    error = NPP_GetValue(0, NPPVpluginDescriptionString, &buffer);
    if (error == NPERR_NO_ERROR)
        plugin.info.desc = buffer;

    const char* mimeDescription = NP_GetMIMEDescription();
    if (!mimeDescription)
        return false;

    setMIMEDescription(mimeDescription, plugin);

    return true;
}
예제 #6
0
void WebIconDatabase::setDatabasePath(const String& path)
{
    if (isOpen()) {
        LOG_ERROR("Icon database already has a path and is already open. We don't currently support changing its path and reopening.");
        return;
    }

    m_iconDatabaseImpl = std::make_unique<IconDatabase>();
    m_iconDatabaseImpl->setClient(this);
    IconDatabase::delayDatabaseCleanup();
    m_databaseCleanupDisabled = true;
    m_iconDatabaseImpl->setEnabled(true);

    // FIXME: WebIconDatabases are per-WebContext but WebContext's don't have their own notion of the current private browsing setting.
    // As we clean up private browsing throughout the stack we need to clean it up here.
    m_iconDatabaseImpl->setPrivateBrowsingEnabled(WebPreferences::anyPagesAreUsingPrivateBrowsing());

    if (!m_iconDatabaseImpl->open(directoryName(path), pathGetFileName(path))) {
        LOG_ERROR("Unable to open WebKit2 icon database on disk");
        m_iconDatabaseImpl = nullptr;
        setGlobalIconDatabase(nullptr);
        IconDatabase::allowDatabaseCleanup();
        m_databaseCleanupDisabled = false;
    }
    setGlobalIconDatabase(m_iconDatabaseImpl.get());
}
예제 #7
0
bool PluginDatabase::fileExistsAndIsNotDisabled(const String& filePath) const
{
    // Skip plugin files that are disabled by filename.
    if (m_disabledPluginFiles.contains(pathGetFileName(filePath)))
        return false;

    return fileExists(filePath);
}
예제 #8
0
static String extractLocaleFromDictionaryFilePath(const String& filePath)
{
    // Dictionary files always have the form "hyph_<locale name>.dic"
    // so we strip everything except the locale.
    String fileName = pathGetFileName(filePath);
    static const int prefixLength = 5;
    static const int suffixLength = 4;
    return fileName.substring(prefixLength, fileName.length() - prefixLength - suffixLength);
}
String directoryName(const String& path)
{
    String name = path.left(path.length() - pathGetFileName(path).length());
    if (name.characterStartingAt(name.length() - 1) == '\\') {
        // Remove any trailing "\".
        name.truncate(name.length() - 1);
    }
    return name;
}
예제 #10
0
파일: File.cpp 프로젝트: 1833183060/wke
File::File(const String& path, const KURL& url, const String& type)
    : Blob(url, type, -1)
    , m_path(path)
{
    m_name = pathGetFileName(path);
    // FIXME: File object serialization/deserialization does not include
    // newer file object data members: m_name and m_relativePath.
    // See SerializedScriptValue.cpp for js and v8.
}
File::File(const String& path, ContentTypeLookupPolicy policy)
    : Blob(createBlobDataForFile(path, policy), -1)
    , m_path(path)
    , m_name(pathGetFileName(path))
#if ENABLE(FILE_SYSTEM)
    , m_snapshotSize(-1)
    , m_snapshotModificationTime(invalidFileTime())
#endif
{
}
예제 #12
0
파일: File.cpp 프로젝트: Spencerx/webkit
File::File(const String& path)
    : Blob(createBlobDataForFile(path), -1)
    , m_path(path)
    , m_name(pathGetFileName(path))
#if ENABLE(FILE_SYSTEM)
    , m_snapshotSize(-1)
    , m_snapshotModificationTime(0)
#endif
{
}
예제 #13
0
PluginPackage::PluginPackage(const String& path, const time_t& lastModified)
    : m_isLoaded(false)
    , m_loadCount(0)
    , m_path(path)
    , m_moduleVersion(0)
    , m_module(0)
    , m_lastModified(lastModified)
    , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired)
{
    m_fileName = pathGetFileName(m_path);
    m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1);
}
예제 #14
0
void StorageTracker::syncFileSystemAndTrackerDatabase()
{
    ASSERT(!isMainThread());

    SQLiteTransactionInProgressAutoCounter transactionCounter;

    ASSERT(m_isActive);

    Vector<String> paths;
    {
        MutexLocker locker(m_databaseMutex);
        paths = listDirectory(m_storageDirectoryPath, "*.localstorage");
    }

    // Use a copy of m_originSet to find expired entries and to schedule their
    // deletions from disk and from m_originSet.
    OriginSet originSetCopy;
    {
        MutexLocker locker(m_originSetMutex);
        for (OriginSet::const_iterator it = m_originSet.begin(), end = m_originSet.end(); it != end; ++it)
            originSetCopy.add((*it).isolatedCopy());
    }
    
    // Add missing StorageTracker records.
    OriginSet foundOrigins;
    String fileExtension = ASCIILiteral(".localstorage");

    for (Vector<String>::const_iterator it = paths.begin(), end = paths.end(); it != end; ++it) {
        const String& path = *it;

        if (path.length() > fileExtension.length() && path.endsWith(fileExtension, true)) {
            String file = pathGetFileName(path);
            String originIdentifier = file.substring(0, file.length() - fileExtension.length());
            if (!originSetCopy.contains(originIdentifier))
                syncSetOriginDetails(originIdentifier, path);

            foundOrigins.add(originIdentifier);
        }
    }

    // Delete stale StorageTracker records.
    for (OriginSet::const_iterator it = originSetCopy.begin(), end = originSetCopy.end(); it != end; ++it) {
        const String& originIdentifier = *it;
        if (foundOrigins.contains(originIdentifier))
            continue;

        String originIdentifierCopy = originIdentifier.isolatedCopy();
        callOnMainThread([this, originIdentifierCopy] {
            deleteOriginWithIdentifier(originIdentifierCopy);
        });
    }
}
예제 #15
0
void File::computeNameAndContentType(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType)
{
#if ENABLE(FILE_REPLACEMENT)
    if (shouldReplaceFile(path)) {
        computeNameAndContentTypeForReplacedFile(path, nameOverride, effectiveName, effectiveContentType);
        return;
    }
#endif
    effectiveName = nameOverride.isNull() ? pathGetFileName(path) : nameOverride;
    size_t index = effectiveName.reverseFind('.');
    if (index != notFound)
        effectiveContentType = MIMETypeRegistry::getMIMETypeForExtension(effectiveName.substring(index + 1));
}
File::File(const String& path, const KURL& url, const String& type)
    : Blob(url, type, -1)
    , m_path(path)
#if ENABLE(FILE_SYSTEM)
    , m_snapshotSize(-1)
    , m_snapshotModificationTime(invalidFileTime())
#endif
{
    m_name = pathGetFileName(path);
    // FIXME: File object serialization/deserialization does not include
    // newer file object data members: m_name and m_relativePath.
    // See SerializedScriptValue.cpp
}
void StorageTracker::syncFileSystemAndTrackerDatabase()
{
    ASSERT(!isMainThread());
    ASSERT(m_isActive);

    m_databaseGuard.lock();
    DEFINE_STATIC_LOCAL(const String, fileMatchPattern, ("*.localstorage"));
    DEFINE_STATIC_LOCAL(const String, fileExt, (".localstorage"));
    DEFINE_STATIC_LOCAL(const unsigned, fileExtLength, (fileExt.length()));
    m_databaseGuard.unlock();

    Vector<String> paths;
    {
        MutexLocker lock(m_databaseGuard);
        paths = listDirectory(m_storageDirectoryPath, fileMatchPattern);
    }

    // Use a copy of m_originSet to find expired entries and to schedule their
    // deletions from disk and from m_originSet.
    OriginSet originSetCopy;
    {
        MutexLocker lock(m_originSetGuard);
        OriginSet::const_iterator end = m_originSet.end();
        for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it)
            originSetCopy.add((*it).threadsafeCopy());
    }
    
    // Add missing StorageTracker records.
    OriginSet foundOrigins;
    Vector<String>::const_iterator end = paths.end();
    for (Vector<String>::const_iterator it = paths.begin(); it != end; ++it) {
        String path = *it;
        if (path.endsWith(fileExt, true) && path.length() > fileExtLength) {
            String file = pathGetFileName(path);
            String originIdentifier = file.substring(0, file.length() - fileExtLength);
            if (!originSetCopy.contains(originIdentifier))
                syncSetOriginDetails(originIdentifier, path);

            foundOrigins.add(originIdentifier);
        }
    }

    // Delete stale StorageTracker records.
    OriginSet::const_iterator setEnd = originSetCopy.end();
    for (OriginSet::const_iterator it = originSetCopy.begin(); it != setEnd; ++it) {
        if (!foundOrigins.contains(*it)) {
            RefPtr<StringImpl> originIdentifier = (*it).threadsafeCopy().impl();
            callOnMainThread(deleteOriginOnMainThread, originIdentifier.release().leakRef());
        }
    }
}
String FileChooser::basenameForWidth(const Font& font, int width) const
{
    if (width <= 0)
        return String();

    String string;
    if (m_filenames.isEmpty())
        string = fileButtonNoFileSelectedLabel();
    else if (m_filenames.size() == 1)
        string = pathGetFileName(m_filenames[0]);
    else
        return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font);

    return StringTruncator::centerTruncate(string, width, font);
}
예제 #19
0
String RenderTheme::fileListNameForWidth(const Vector<String>& filenames, const Font& font, int width)
{
    if (width <= 0)
        return String();

    String string;
    if (filenames.isEmpty())
        string = fileButtonNoFileSelectedLabel();
    else if (filenames.size() == 1)
        string = pathGetFileName(filenames[0]);
    else
        return StringTruncator::rightTruncate(multipleFileUploadText(filenames.size()), width, font, StringTruncator::EnableRoundingHacks);

    return StringTruncator::centerTruncate(string, width, font, StringTruncator::EnableRoundingHacks);
}
예제 #20
0
Vector<RefPtr<WebCore::SecurityOrigin>> DatabaseProcess::indexedDatabaseOrigins()
{
    if (m_indexedDatabaseDirectory.isEmpty())
        return { };

    Vector<RefPtr<WebCore::SecurityOrigin>> securityOrigins;
    for (auto& originPath : listDirectory(m_indexedDatabaseDirectory, "*")) {
        String databaseIdentifier = pathGetFileName(originPath);

        if (auto securityOrigin = SecurityOrigin::maybeCreateFromDatabaseIdentifier(databaseIdentifier))
            securityOrigins.append(WTFMove(securityOrigin));
    }

    return securityOrigins;
}
예제 #21
0
PluginPackage::PluginPackage(const String& path, const time_t& lastModified)
    : m_isEnabled(true)
    , m_isLoaded(false)
    , m_loadCount(0)
    , m_path(path)
    , m_moduleVersion(0)
    , m_module(0)
    , m_lastModified(lastModified)
    , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired)
#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
    , m_infoIsFromCache(true)
#endif
{
    m_fileName = pathGetFileName(m_path);
    m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1);
}
예제 #22
0
bool NetscapePluginModule::getPluginInfo(const String& pluginPath, PluginModuleInfo& plugin)
{
    RawPluginMetaData metaData;
    if (!PluginProcessProxy::scanPlugin(pluginPath, metaData))
        return false;

    plugin.path = pluginPath;
    plugin.info.file = pathGetFileName(pluginPath);
    plugin.info.name = metaData.name;
    plugin.info.desc = metaData.description;
    parseMIMEDescription(metaData.mimeDescription, plugin.info.mimes);
#if PLATFORM(GTK)
    plugin.requiresGtk2 = metaData.requiresGtk2;
#endif

    return true;
}
예제 #23
0
String RenderThemeGtk::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const
{
    if (width <= 0)
        return String();

    if (fileList->length() > 1)
        return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks);

    String string;
    if (fileList->length())
        string = pathGetFileName(fileList->item(0)->path());
    else if (multipleFilesAllowed)
        string = fileButtonNoFilesSelectedLabel();
    else
        string = fileButtonNoFileSelectedLabel();

    return StringTruncator::centerTruncate(string, width, font, StringTruncator::EnableRoundingHacks);
}
예제 #24
0
static Optional<FileMetadata> fileMetadataUsingFunction(const String& path, int (*statFunc)(const char*, struct stat*))
{
    CString fsRep = fileSystemRepresentation(path);

    if (!fsRep.data() || fsRep.data()[0] == '\0')
        return WTF::nullopt;

    struct stat fileInfo;
    if (statFunc(fsRep.data(), &fileInfo))
        return WTF::nullopt;

    String filename = pathGetFileName(path);
    bool isHidden = !filename.isEmpty() && filename[0] == '.';
    return FileMetadata {
        WallTime::fromRawSeconds(fileInfo.st_mtime),
        fileInfo.st_size,
        isHidden,
        toFileMetataType(fileInfo)
    };
}
예제 #25
0
void WebIconDatabase::setDatabasePath(const String& path)
{
    if (isOpen()) {
        LOG_ERROR("Icon database already has a path and is already open. We don't currently support changing its path and reopening.");
        return;
    }

    m_iconDatabaseImpl =  IconDatabase::create();
    m_iconDatabaseImpl->setClient(this);
    IconDatabase::delayDatabaseCleanup();
    m_databaseCleanupDisabled = true;
    m_iconDatabaseImpl->setEnabled(true);
    if (!m_iconDatabaseImpl->open(directoryName(path), pathGetFileName(path))) {
        LOG_ERROR("Unable to open WebKit2 icon database on disk");
        m_iconDatabaseImpl.clear();
        setGlobalIconDatabase(0);
        IconDatabase::allowDatabaseCleanup();
        m_databaseCleanupDisabled = false;
    }
    setGlobalIconDatabase(m_iconDatabaseImpl.get());
}
예제 #26
0
void DatabaseTracker::removeDeletedOpenedDatabases()
{
    // This is called when another app has deleted a database.  Go through all opened databases in this
    // tracker and close any that's no longer being tracked in the database.
    
    {
        // Acquire the lock before calling openTrackerDatabase.
        LockHolder lockDatabase(m_databaseGuard);
        openTrackerDatabase(DontCreateIfDoesNotExist);
    }

    if (!m_database.isOpen())
        return;
    
    // Keep track of which opened databases have been deleted.
    Vector<RefPtr<Database> > deletedDatabases;
    typedef HashMap<RefPtr<SecurityOrigin>, Vector<String> > DeletedDatabaseMap;
    DeletedDatabaseMap deletedDatabaseMap;
    
    // Make sure not to hold the m_openDatabaseMapGuard mutex when calling
    // Database::markAsDeletedAndClose(), since that can cause a deadlock
    // during the synchronous DatabaseThread call it triggers.
    {
        LockHolder openDatabaseMapLock(m_openDatabaseMapGuard);
        if (m_openDatabaseMap) {
            for (auto& openDatabase : *m_openDatabaseMap) {
                auto& origin = openDatabase.key;
                DatabaseNameMap* databaseNameMap = openDatabase.value;
                Vector<String> deletedDatabaseNamesForThisOrigin;

                // Loop through all opened databases in this origin.  Get the current database file path of each database and see if
                // it still matches the path stored in the opened database object.
                for (auto& databases : *databaseNameMap) {
                    String databaseName = databases.key;
                    String databaseFileName;
                    SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
                    if (statement.prepare() == SQLITE_OK) {
                        statement.bindText(1, origin->databaseIdentifier());
                        statement.bindText(2, databaseName);
                        if (statement.step() == SQLITE_ROW)
                            databaseFileName = statement.getColumnText(0);
                        statement.finalize();
                    }
                    
                    bool foundDeletedDatabase = false;
                    for (auto& db : *databases.value) {
                        // We are done if this database has already been marked as deleted.
                        if (db->deleted())
                            continue;
                        
                        // If this database has been deleted or if its database file no longer matches the current version, this database is no longer valid and it should be marked as deleted.
                        if (databaseFileName.isNull() || databaseFileName != pathGetFileName(db->fileName())) {
                            deletedDatabases.append(db);
                            foundDeletedDatabase = true;
                        }
                    }
                    
                    // If the database no longer exists, we should remember to remove it from the OriginQuotaManager later.
                    if (foundDeletedDatabase && databaseFileName.isNull())
                        deletedDatabaseNamesForThisOrigin.append(databaseName);
                }
                
                if (!deletedDatabaseNamesForThisOrigin.isEmpty())
                    deletedDatabaseMap.set(origin, deletedDatabaseNamesForThisOrigin);
            }
        }
    }
    
    for (auto& deletedDatabase : deletedDatabases)
        deletedDatabase->markAsDeletedAndClose();

    for (auto& deletedDatabase : deletedDatabaseMap) {
        SecurityOrigin* origin = deletedDatabase.key.get();
        if (m_client)
            m_client->dispatchDidModifyOrigin(origin);
        
        const Vector<String>& databaseNames = deletedDatabase.value;
        for (auto& databaseName : databaseNames) {
            if (m_client)
                m_client->dispatchDidModifyDatabase(origin, databaseName);
        }        
    }
}
String pathGetDisplayFileName(const String& path)
{
    return pathGetFileName(path);
}
File::File(const String& path, const KURL& url, const String& type)
    : Blob(url, type, -1)
    , m_path(path)
{
    m_name = pathGetFileName(path);
}
File::File(const String& path)
    : Blob(createBlobDataForFile(path), -1)
    , m_path(path)
    , m_name(pathGetFileName(path))
{
}
예제 #30
0
bool PluginInfoStore::shouldUsePlugin(Vector<PluginModuleInfo>& alreadyLoadedPlugins, const PluginModuleInfo& plugin)
{
    if (plugin.info.name == "Citrix ICA Client") {
        // The Citrix ICA Client plug-in requires a Mozilla-based browser; see <rdar://6418681>.
        return false;
    }

    if (plugin.info.name == "Silverlight Plug-In") {
        // workaround for <rdar://5557379> Crash in Silverlight when opening microsoft.com.
        // the latest 1.0 version of Silverlight does not reproduce this crash, so allow it
        // and any newer versions
        static const uint64_t minimumRequiredVersion = fileVersion(0x51BE0000, 0x00010000);
        return plugin.fileVersion >= minimumRequiredVersion;
    }

    if (equalIgnoringCase(plugin.info.file, "npmozax.dll")) {
        // Bug 15217: Mozilla ActiveX control complains about missing xpcom_core.dll
        return false;
    }

    if (equalIgnoringCase(plugin.info.file, "npwpf.dll")) {
        // Bug 57119: Microsoft Windows Presentation Foundation (WPF) plug-in complains about missing xpcom.dll
        return false;
    }

    if (plugin.info.name == "Yahoo Application State Plugin") {
        // https://bugs.webkit.org/show_bug.cgi?id=26860
        // Bug in Yahoo Application State plug-in earlier than 1.0.0.6 leads to heap corruption.
        static const uint64_t minimumRequiredVersion = fileVersion(0x00000006, 0x00010000);
        return plugin.fileVersion >= minimumRequiredVersion;
    }

    if (isOldWindowsMediaPlayerPlugin(plugin)) {
        // Don't load the old Windows Media Player plugin if we've already loaded the new Windows
        // Media Player plugin.
        for (size_t i = 0; i < alreadyLoadedPlugins.size(); ++i) {
            if (!isNewWindowsMediaPlayerPlugin(alreadyLoadedPlugins[i]))
                continue;
            return false;
        }
        return true;
    }

    if (isNewWindowsMediaPlayerPlugin(plugin)) {
        // Remove the old Windows Media Player plugin if we've already added it.
        for (size_t i = 0; i < alreadyLoadedPlugins.size(); ++i) {
            if (!isOldWindowsMediaPlayerPlugin(alreadyLoadedPlugins[i]))
                continue;
            alreadyLoadedPlugins.remove(i);
        }
        return true;
    }

    // FIXME: We should prefer a newer version of a plugin to an older version, rather than loading
    // only the first. <http://webkit.org/b/58469>
    String pluginFileName = pathGetFileName(plugin.path);
    for (size_t i = 0; i < alreadyLoadedPlugins.size(); ++i) {
        const PluginModuleInfo& loadedPlugin = alreadyLoadedPlugins[i];

        // If a plug-in with the same filename already exists, we don't want to load it.
        if (equalIgnoringCase(pluginFileName, pathGetFileName(loadedPlugin.path)))
            return false;
    }

    return true;
}