<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Logger.h"

#include "OSHelper.h"
#include "Exception.h"
#include "StandardLogSink.h"

#ifdef _WIN32
#include <Winsock2.h>
#include <time.h>
#include <Mmsystem.h>
#undef ERROR
#else
#include <sys/time.h>
#include <syslog.h>
#endif
#include <iostream>
#include <iomanip>
#include <boost/thread.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;

namespace avg {

    const unsigned Logger::severity::CRITICAL = 50;
    const unsigned Logger::severity::ERROR = 40;
    const unsigned Logger::severity::WARNING = 30;
    const unsigned Logger::severity::INFO = 20;
    const unsigned Logger::severity::DEBUG = 10;

    const size_t Logger::category::NONE = 1;
    const size_t Logger::category::PROFILE = 2;
    const size_t Logger::category::PROFILE_VIDEO = 8;
    const size_t Logger::category::EVENTS = 16;
    const size_t Logger::category::CONFIG = 64;
    const size_t Logger::category::MEMORY = 512;
    const size_t Logger::category::APP = 1024;
    const size_t Logger::category::PLUGIN = 2048;
    const size_t Logger::category::PLAYER = 4096;
    const size_t Logger::category::SHADER = 8192;
    const size_t Logger::category::DEPRECATION = 16384;
    const size_t Logger::category::LAST_CATEGORY = DEPRECATION;

namespace {
    Logger* m_pLogger = 0;
    std::vector<LogSinkPtr> m_Sinks;
    boost::mutex logMutex;
    boost::mutex sinkMutex;
}

Logger * Logger::get()
{
    boost::mutex::scoped_lock lock(logMutex);
    if (!m_pLogger) {
        m_pLogger = new Logger;
    }
    return m_pLogger;
}

Logger::Logger()
{
    setupCategory();
    m_Severity = severity::INFO;
    string sEnvSeverity;
    bool bEnvSeveritySet = getEnv("AVG_LOG_severity", sEnvSeverity);
    if(bEnvSeveritySet){
        m_Severity = Logger::stringToSeverity(sEnvSeverity);
    }
    m_Flags = category::NONE | category::APP | category::DEPRECATION;
    string sEnvCategories;
    bool bEnvSet = getEnv("AVG_LOG_CATEGORIES", sEnvCategories);
    if (bEnvSet) {
        m_Flags = category::NONE;
        bool bDone = false;
        string sCategory;
        do {
            string::size_type pos = sEnvCategories.find(":");
            if (pos == string::npos) {
                sCategory = sEnvCategories;
                bDone = true;
            } else {
                sCategory = sEnvCategories.substr(0, pos);
                sEnvCategories = sEnvCategories.substr(pos+1);
            }
            size_t category = stringToCategory(sCategory);
            m_Flags |= category;
            } while (!bDone);
    }
    m_MaxCategoryNum = category::LAST_CATEGORY;

    string sDummy;
    bool bEnvUseStdErr = getEnv("AVG_LOG_OMIT_STDERR", sDummy);
    if (!bEnvUseStdErr) {
        addLogSink(LogSinkPtr(new StandardLogSink));
    }
}

Logger::~Logger()
{
}

size_t Logger::getCategories() const
{
    boost::mutex::scoped_lock lock(logMutex);
    return m_Flags;
}

void Logger::setCategories(size_t flags)
{
    boost::mutex::scoped_lock lock(logMutex);
    m_Flags = flags;
}

void Logger::setLogSeverity(unsigned severity){
        m_Severity = severity;
}

void Logger::pushCategories()
{
    boost::mutex::scoped_lock lock(logMutex);
    m_FlagStack.push_back(m_Flags);
}

void Logger::popCategories()
{
    boost::mutex::scoped_lock lock(logMutex);
    if (m_FlagStack.empty()) {
        throw Exception(AVG_ERR_OUT_OF_RANGE, "popCategories: Nothing to pop.");
    }
    m_Flags = m_FlagStack.back();
    m_FlagStack.pop_back();
}

void Logger::addLogSink(const LogSinkPtr& logSink)
{
    boost::mutex::scoped_lock lock(sinkMutex);
    m_Sinks.push_back(logSink);
}

void Logger::removeLogSink(const LogSinkPtr& logSink)
{
    boost::mutex::scoped_lock lock(sinkMutex);
    std::vector<LogSinkPtr>::iterator it;
    it = find(m_Sinks.begin(), m_Sinks.end(), logSink);
    if ( it != m_Sinks.end() ){
        m_Sinks.erase(it);
    }
}

void Logger::trace(const UTF8String& sMsg, size_t category, unsigned severity) const
{
    boost::mutex::scoped_lock lock(logMutex);
    struct tm* pTime;
    #ifdef _WIN32
    __int64 now;
    _time64(&now);
    pTime = _localtime64(&now);
    DWORD tms = timeGetTime();
    unsigned millis = unsigned(tms % 1000);
    #else
    struct timeval time;
    gettimeofday(&time, NULL);
    pTime = localtime(&time.tv_sec);
    unsigned millis = time.tv_usec/1000;
    #endif
    string sCategory = categoryToString(category);
    boost::mutex::scoped_lock lockHandler(sinkMutex);
    std::vector<LogSinkPtr>::iterator it;
    for(it=m_Sinks.begin(); it!=m_Sinks.end(); ++it){
        (*it)->logMessage(pTime, millis, sCategory, severity, sMsg);
    }
}

size_t Logger::registerCategory(const string& cat){
    std::map< string, size_t >::iterator it;
    it = m_StringToCategory.find(cat);
    if(it != m_StringToCategory.end()){
        return it->second;
    }else{
        m_MaxCategoryNum *= 2;
        m_CategoryToString[m_MaxCategoryNum] = cat;
        m_StringToCategory[cat] = m_MaxCategoryNum;
        return m_MaxCategoryNum;
    }
}

void Logger::logDebug(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::DEBUG);
}

void Logger::logInfo(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::INFO);
}

void Logger::logWarning(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::WARNING);
}

void Logger::logError(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::ERROR);
}

void Logger::logCritical(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::CRITICAL);
}

void Logger::log(const string& msg, const size_t category, unsigned severity) const
{
    if( shouldLog(category, severity)){
        trace(msg, category, severity);
    }
}

const char * Logger::categoryToString(size_t category) const
{
    std::map< size_t, string >::const_iterator it;
    it = m_CategoryToString.find(category);
    if(it != m_CategoryToString.end()){
        return (it->second).c_str();
    }else{
        return "UNKNOWN";
    }
}

size_t Logger::stringToCategory(const string& sCategory) const
{
    std::map< string , size_t >::const_iterator it;
    it = m_StringToCategory.find(sCategory);
    if(it != m_StringToCategory.end()){
        return it->second;
    }else{
        throw Exception (AVG_ERR_INVALID_ARGS, "Unknown logging category " + sCategory
                + " set using AVG_LOG_CATEGORIES.");
    }
}

void Logger::setupCategory(){
    m_CategoryToString[category::NONE] = "NONE";
    m_StringToCategory["NONE"] = category::NONE;

    m_CategoryToString[category::PROFILE] = "PROFILE",
    m_StringToCategory["PROFILE"] = category::PROFILE;

    m_CategoryToString[category::PROFILE_VIDEO] = "PROFILE_VIDEO";
    m_StringToCategory["PROFILE_VIDEO"] = category::PROFILE_VIDEO;

    m_CategoryToString[category::EVENTS] = "EVENTS";
    m_StringToCategory["EVENTS"] = category::EVENTS;

    m_CategoryToString[category::CONFIG] = "CONFIG";
    m_StringToCategory["CONFIG"] = category::CONFIG;

    m_CategoryToString[category::MEMORY] = "MEMORY";
    m_StringToCategory["MEMORY"] = category::MEMORY;

    m_CategoryToString[category::APP] = "APP";
    m_StringToCategory["APP"] = category::APP;

    m_CategoryToString[category::PLUGIN] = "PLUGIN";
    m_StringToCategory["PLUGIN"] = category::PLUGIN;

    m_CategoryToString[category::PLAYER] = "PLAYER";
    m_StringToCategory["PLAYER"] = category::PLAYER;

    m_CategoryToString[category::SHADER] = "SHADER";
    m_StringToCategory["SHADER"] = category::SHADER;

    m_CategoryToString[category::DEPRECATION] = "DEPRECATION";
    m_StringToCategory["DEPRECATION"] = category::DEPRECATION;
}

unsigned Logger::stringToSeverity(const string& sSeverity)
{
    string severity = boost::to_upper_copy(sSeverity);
    if (severity == "CRITICAL"){
        return Logger::severity::CRITICAL;
    }else if (severity == "ERROR"){
        return Logger::severity::ERROR;
    }else if (severity == "WARNING"){
        return Logger::severity::WARNING;
    }else if (severity == "INFO"){
        return Logger::severity::INFO;
    }else if (severity == "DEBUG"){
        return Logger::severity::DEBUG;
    }
    throw Exception(AVG_ERR_INVALID_ARGS, severity + " is an invalid log severity");
}

const char * Logger::severityToString(unsigned severity)
{
    if(severity == Logger::severity::CRITICAL){
        return "CRITICAL";
    }else if(severity == Logger::severity::ERROR){
        return "ERROR";
    }else if(severity == Logger::severity::WARNING){
        return "WARNING";
    }else if(severity == Logger::severity::INFO){
        return "INFO";
    }else if(severity == Logger::severity::DEBUG){
        return "DEBUG";
    }
    throw Exception(AVG_ERR_UNKNOWN, "Unkown log severity");
}

}
<commit_msg>logging branch: Fixed typo<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Logger.h"

#include "OSHelper.h"
#include "Exception.h"
#include "StandardLogSink.h"

#ifdef _WIN32
#include <Winsock2.h>
#include <time.h>
#include <Mmsystem.h>
#undef ERROR
#else
#include <sys/time.h>
#include <syslog.h>
#endif
#include <iostream>
#include <iomanip>
#include <boost/thread.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;

namespace avg {

    const unsigned Logger::severity::CRITICAL = 50;
    const unsigned Logger::severity::ERROR = 40;
    const unsigned Logger::severity::WARNING = 30;
    const unsigned Logger::severity::INFO = 20;
    const unsigned Logger::severity::DEBUG = 10;

    const size_t Logger::category::NONE = 1;
    const size_t Logger::category::PROFILE = 2;
    const size_t Logger::category::PROFILE_VIDEO = 8;
    const size_t Logger::category::EVENTS = 16;
    const size_t Logger::category::CONFIG = 64;
    const size_t Logger::category::MEMORY = 512;
    const size_t Logger::category::APP = 1024;
    const size_t Logger::category::PLUGIN = 2048;
    const size_t Logger::category::PLAYER = 4096;
    const size_t Logger::category::SHADER = 8192;
    const size_t Logger::category::DEPRECATION = 16384;
    const size_t Logger::category::LAST_CATEGORY = DEPRECATION;

namespace {
    Logger* m_pLogger = 0;
    std::vector<LogSinkPtr> m_Sinks;
    boost::mutex logMutex;
    boost::mutex sinkMutex;
}

Logger * Logger::get()
{
    boost::mutex::scoped_lock lock(logMutex);
    if (!m_pLogger) {
        m_pLogger = new Logger;
    }
    return m_pLogger;
}

Logger::Logger()
{
    setupCategory();
    m_Severity = severity::INFO;
    string sEnvSeverity;
    bool bEnvSeveritySet = getEnv("AVG_LOG_SEVERITY", sEnvSeverity);
    if(bEnvSeveritySet){
        m_Severity = Logger::stringToSeverity(sEnvSeverity);
    }
    m_Flags = category::NONE | category::APP | category::DEPRECATION;
    string sEnvCategories;
    bool bEnvSet = getEnv("AVG_LOG_CATEGORIES", sEnvCategories);
    if (bEnvSet) {
        m_Flags = category::NONE;
        bool bDone = false;
        string sCategory;
        do {
            string::size_type pos = sEnvCategories.find(":");
            if (pos == string::npos) {
                sCategory = sEnvCategories;
                bDone = true;
            } else {
                sCategory = sEnvCategories.substr(0, pos);
                sEnvCategories = sEnvCategories.substr(pos+1);
            }
            size_t category = stringToCategory(sCategory);
            m_Flags |= category;
            } while (!bDone);
    }
    m_MaxCategoryNum = category::LAST_CATEGORY;

    string sDummy;
    bool bEnvUseStdErr = getEnv("AVG_LOG_OMIT_STDERR", sDummy);
    if (!bEnvUseStdErr) {
        addLogSink(LogSinkPtr(new StandardLogSink));
    }
}

Logger::~Logger()
{
}

size_t Logger::getCategories() const
{
    boost::mutex::scoped_lock lock(logMutex);
    return m_Flags;
}

void Logger::setCategories(size_t flags)
{
    boost::mutex::scoped_lock lock(logMutex);
    m_Flags = flags;
}

void Logger::setLogSeverity(unsigned severity){
        m_Severity = severity;
}

void Logger::pushCategories()
{
    boost::mutex::scoped_lock lock(logMutex);
    m_FlagStack.push_back(m_Flags);
}

void Logger::popCategories()
{
    boost::mutex::scoped_lock lock(logMutex);
    if (m_FlagStack.empty()) {
        throw Exception(AVG_ERR_OUT_OF_RANGE, "popCategories: Nothing to pop.");
    }
    m_Flags = m_FlagStack.back();
    m_FlagStack.pop_back();
}

void Logger::addLogSink(const LogSinkPtr& logSink)
{
    boost::mutex::scoped_lock lock(sinkMutex);
    m_Sinks.push_back(logSink);
}

void Logger::removeLogSink(const LogSinkPtr& logSink)
{
    boost::mutex::scoped_lock lock(sinkMutex);
    std::vector<LogSinkPtr>::iterator it;
    it = find(m_Sinks.begin(), m_Sinks.end(), logSink);
    if ( it != m_Sinks.end() ){
        m_Sinks.erase(it);
    }
}

void Logger::trace(const UTF8String& sMsg, size_t category, unsigned severity) const
{
    boost::mutex::scoped_lock lock(logMutex);
    struct tm* pTime;
    #ifdef _WIN32
    __int64 now;
    _time64(&now);
    pTime = _localtime64(&now);
    DWORD tms = timeGetTime();
    unsigned millis = unsigned(tms % 1000);
    #else
    struct timeval time;
    gettimeofday(&time, NULL);
    pTime = localtime(&time.tv_sec);
    unsigned millis = time.tv_usec/1000;
    #endif
    string sCategory = categoryToString(category);
    boost::mutex::scoped_lock lockHandler(sinkMutex);
    std::vector<LogSinkPtr>::iterator it;
    for(it=m_Sinks.begin(); it!=m_Sinks.end(); ++it){
        (*it)->logMessage(pTime, millis, sCategory, severity, sMsg);
    }
}

size_t Logger::registerCategory(const string& cat){
    std::map< string, size_t >::iterator it;
    it = m_StringToCategory.find(cat);
    if(it != m_StringToCategory.end()){
        return it->second;
    }else{
        m_MaxCategoryNum *= 2;
        m_CategoryToString[m_MaxCategoryNum] = cat;
        m_StringToCategory[cat] = m_MaxCategoryNum;
        return m_MaxCategoryNum;
    }
}

void Logger::logDebug(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::DEBUG);
}

void Logger::logInfo(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::INFO);
}

void Logger::logWarning(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::WARNING);
}

void Logger::logError(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::ERROR);
}

void Logger::logCritical(const string& msg, const size_t category) const
{
    log(msg, category, Logger::severity::CRITICAL);
}

void Logger::log(const string& msg, const size_t category, unsigned severity) const
{
    if( shouldLog(category, severity)){
        trace(msg, category, severity);
    }
}

const char * Logger::categoryToString(size_t category) const
{
    std::map< size_t, string >::const_iterator it;
    it = m_CategoryToString.find(category);
    if(it != m_CategoryToString.end()){
        return (it->second).c_str();
    }else{
        return "UNKNOWN";
    }
}

size_t Logger::stringToCategory(const string& sCategory) const
{
    std::map< string , size_t >::const_iterator it;
    it = m_StringToCategory.find(sCategory);
    if(it != m_StringToCategory.end()){
        return it->second;
    }else{
        throw Exception (AVG_ERR_INVALID_ARGS, "Unknown logging category " + sCategory
                + " set using AVG_LOG_CATEGORIES.");
    }
}

void Logger::setupCategory(){
    m_CategoryToString[category::NONE] = "NONE";
    m_StringToCategory["NONE"] = category::NONE;

    m_CategoryToString[category::PROFILE] = "PROFILE",
    m_StringToCategory["PROFILE"] = category::PROFILE;

    m_CategoryToString[category::PROFILE_VIDEO] = "PROFILE_VIDEO";
    m_StringToCategory["PROFILE_VIDEO"] = category::PROFILE_VIDEO;

    m_CategoryToString[category::EVENTS] = "EVENTS";
    m_StringToCategory["EVENTS"] = category::EVENTS;

    m_CategoryToString[category::CONFIG] = "CONFIG";
    m_StringToCategory["CONFIG"] = category::CONFIG;

    m_CategoryToString[category::MEMORY] = "MEMORY";
    m_StringToCategory["MEMORY"] = category::MEMORY;

    m_CategoryToString[category::APP] = "APP";
    m_StringToCategory["APP"] = category::APP;

    m_CategoryToString[category::PLUGIN] = "PLUGIN";
    m_StringToCategory["PLUGIN"] = category::PLUGIN;

    m_CategoryToString[category::PLAYER] = "PLAYER";
    m_StringToCategory["PLAYER"] = category::PLAYER;

    m_CategoryToString[category::SHADER] = "SHADER";
    m_StringToCategory["SHADER"] = category::SHADER;

    m_CategoryToString[category::DEPRECATION] = "DEPRECATION";
    m_StringToCategory["DEPRECATION"] = category::DEPRECATION;
}

unsigned Logger::stringToSeverity(const string& sSeverity)
{
    string severity = boost::to_upper_copy(sSeverity);
    if (severity == "CRITICAL"){
        return Logger::severity::CRITICAL;
    }else if (severity == "ERROR"){
        return Logger::severity::ERROR;
    }else if (severity == "WARNING"){
        return Logger::severity::WARNING;
    }else if (severity == "INFO"){
        return Logger::severity::INFO;
    }else if (severity == "DEBUG"){
        return Logger::severity::DEBUG;
    }
    throw Exception(AVG_ERR_INVALID_ARGS, severity + " is an invalid log severity");
}

const char * Logger::severityToString(unsigned severity)
{
    if(severity == Logger::severity::CRITICAL){
        return "CRITICAL";
    }else if(severity == Logger::severity::ERROR){
        return "ERROR";
    }else if(severity == Logger::severity::WARNING){
        return "WARNING";
    }else if(severity == Logger::severity::INFO){
        return "INFO";
    }else if(severity == Logger::severity::DEBUG){
        return "DEBUG";
    }
    throw Exception(AVG_ERR_UNKNOWN, "Unkown log severity");
}

}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "factory.h"
#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtGui/QIcon>
#ifndef QT_NO_DBUS
#include <QtDBus/QtDBus>
#endif

namespace Phonon
{

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::setBackend(QObject *b)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    globalFactory->m_backendObject = b;
}

/*void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}*/

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default
        // (finding the first loadable backend).
        const QLatin1String suffix("/phonon_backend/");
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (QString pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  load failed:"
                             << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }

                // no backend found, don't leave an unused plugin in memory
                pluginLoader.unload();
            }

            if (m_backendObject) {
                break;
            }
        }
        if (!m_backendObject) {
            pWarning() << Q_FUNC_INFO << "phonon backend plugin could not be loaded";
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (!m_platformPlugin) {
        if (m_noPlatformPlugin) {
            return 0;
        }
#ifndef QT_NO_DBUS
        if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
            pWarning() << "Phonon needs QCoreApplication::applicationName to be set to export audio output names through the DBUS interface";
        }
#endif
        const QString suffix(QLatin1String("/phonon_platform"));
        Q_ASSERT(QCoreApplication::instance());
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  platform plugin load failed:"
                        << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_platformPlugin = qobject_cast<PlatformPlugin *>(pluginLoader.instance());
                pDebug() << m_platformPlugin;
                if (m_platformPlugin) {
                    return m_platformPlugin;
                } else {
                    pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the KDE platform plugin was not loadable:" << pluginLoader.errorString();
                    pluginLoader.unload();
                }
            }
        }
        if (!m_platformPlugin) {
            pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
            m_noPlatformPlugin = true;
        }
    }
    return m_platformPlugin;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (globalFactory.isDestroyed()) {
        return 0;
    }
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

#include "moc_factory.cpp"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<commit_msg>SVN_SILENT: does not have to be the KDE platform plugin anymore<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "factory.h"
#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtGui/QIcon>
#ifndef QT_NO_DBUS
#include <QtDBus/QtDBus>
#endif

namespace Phonon
{

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::setBackend(QObject *b)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    globalFactory->m_backendObject = b;
}

/*void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}*/

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default
        // (finding the first loadable backend).
        const QLatin1String suffix("/phonon_backend/");
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (QString pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  load failed:"
                             << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }

                // no backend found, don't leave an unused plugin in memory
                pluginLoader.unload();
            }

            if (m_backendObject) {
                break;
            }
        }
        if (!m_backendObject) {
            pWarning() << Q_FUNC_INFO << "phonon backend plugin could not be loaded";
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (!m_platformPlugin) {
        if (m_noPlatformPlugin) {
            return 0;
        }
#ifndef QT_NO_DBUS
        if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
            pWarning() << "Phonon needs QCoreApplication::applicationName to be set to export audio output names through the DBUS interface";
        }
#endif
        const QString suffix(QLatin1String("/phonon_platform"));
        Q_ASSERT(QCoreApplication::instance());
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  platform plugin load failed:"
                        << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_platformPlugin = qobject_cast<PlatformPlugin *>(pluginLoader.instance());
                pDebug() << m_platformPlugin;
                if (m_platformPlugin) {
                    return m_platformPlugin;
                } else {
                    pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the platform plugin was not loadable:" << pluginLoader.errorString();
                    pluginLoader.unload();
                }
            }
        }
        if (!m_platformPlugin) {
            pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
            m_noPlatformPlugin = true;
        }
    }
    return m_platformPlugin;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (globalFactory.isDestroyed()) {
        return 0;
    }
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

#include "moc_factory.cpp"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<|endoftext|>


<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_LOR
#define MFEM_LOR

#include "bilinearform.hpp"

namespace mfem
{

/// Abstract base class for LOR and ParLOR classes, which construct low-order
/// refined versions of bilinear forms.
class LORBase
{
private:
   using GetIntegratorsFn = Array<BilinearFormIntegrator*> *(BilinearForm::*)();
   using GetMarkersFn = Array<Array<int>*> *(BilinearForm::*)();
   using AddIntegratorFn = void (BilinearForm::*)(BilinearFormIntegrator*);
   using AddIntegratorMarkersFn =
      void (BilinearForm::*)(BilinearFormIntegrator*, Array<int>&);

   BilinearForm &a;
   IntegrationRules irs;
   const IntegrationRule *ir;
   std::map<BilinearFormIntegrator*, const IntegrationRule*> ir_map;

   void AddIntegrators(BilinearForm &a_to,
                       GetIntegratorsFn get_integrators,
                       AddIntegratorFn add_integrator);

   void AddIntegratorsAndMarkers(BilinearForm &a_to,
                                 GetIntegratorsFn get_integrators,
                                 GetMarkersFn get_markers,
                                 AddIntegratorMarkersFn add_integrator);

   void ResetIntegrationRules(GetIntegratorsFn get_integrators);

protected:
   /// Adds all the integrators from the member data @a a to the BilinearForm
   /// @a a_to. Marks @a a_to as using external integrators. If the mesh
   /// consists of tensor product elements, temporarily changes the integration
   /// rules of the integrators to use collocated quadrature for better
   /// conditioning of the LOR system.
   void AddIntegrators(BilinearForm &a_to);

   /// Resets the integration rules of the integrators of @a a to their original
   /// values.
   void ResetIntegrationRules();

   LORBase(BilinearForm &a_);
};

class LOR : LORBase
{
protected:
   Mesh mesh;
   FiniteElementCollection *fec;
   FiniteElementSpace *fes;
   BilinearForm *a;
   SparseMatrix A;

public:
   LOR(BilinearForm &a_ho, const Array<int> &ess_tdof_list,
       int ref_type=BasisType::GaussLobatto);

   SparseMatrix &GetAssembledMatrix();

   ~LOR();
};

template <typename SolverType>
class LORSolver : public Solver
{
protected:
   LOR lor;
   SolverType solver;
public:
   LORSolver(BilinearForm &a_ho, const Array<int> &ess_tdof_list,
             int ref_type=BasisType::GaussLobatto)
      : lor(a_ho, ess_tdof_list, ref_type),
        solver(lor.GetAssembledMatrix())
   { }

   void SetOperator(const Operator &op)
   {
      if (&op != &lor.GetAssembledMatrix())
      {
         MFEM_ABORT("LORSolver::SetOperator not supported.")
      }
   }

   void Mult(const Vector &x, Vector &y) const
   {
      solver.Mult(x, y);
   }
};

#ifdef MFEM_USE_MPI

class ParLOR : public LORBase
{
protected:
   ParMesh mesh;
   FiniteElementCollection *fec;
   ParFiniteElementSpace *fes;
   ParBilinearForm *a;
   HypreParMatrix A;

public:
   ParLOR(ParBilinearForm &a_ho, const Array<int> &ess_tdof_list,
          int ref_type=BasisType::GaussLobatto);

   HypreParMatrix &GetAssembledMatrix();

   ~ParLOR();
};

template <typename SolverType>
class ParLORSolver : public Solver
{
protected:
   ParLOR lor;
   SolverType solver;
public:
   ParLORSolver(ParBilinearForm &a_ho, const Array<int> &ess_tdof_list,
                int ref_type=BasisType::GaussLobatto)
      : lor(a_ho, ess_tdof_list, ref_type),
        solver(lor.GetAssembledMatrix())
   { }

   void SetOperator(const Operator &op)
   {
      if (&op != &lor.GetAssembledMatrix())
      {
         MFEM_ABORT("ParLORSolver::SetOperator not supported.")
      }
   }

   void Mult(const Vector &x, Vector &y) const
   {
      solver.Mult(x, y);
   }
};

#endif

} // namespace mfem

#endif
<commit_msg>Document LOR classes<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_LOR
#define MFEM_LOR

#include "bilinearform.hpp"

namespace mfem
{

/// Abstract base class for LOR and ParLOR classes, which construct low-order
/// refined versions of bilinear forms.
class LORBase
{
private:
   using GetIntegratorsFn = Array<BilinearFormIntegrator*> *(BilinearForm::*)();
   using GetMarkersFn = Array<Array<int>*> *(BilinearForm::*)();
   using AddIntegratorFn = void (BilinearForm::*)(BilinearFormIntegrator*);
   using AddIntegratorMarkersFn =
      void (BilinearForm::*)(BilinearFormIntegrator*, Array<int>&);

   BilinearForm &a;
   IntegrationRules irs;
   const IntegrationRule *ir;
   std::map<BilinearFormIntegrator*, const IntegrationRule*> ir_map;

   void AddIntegrators(BilinearForm &a_to,
                       GetIntegratorsFn get_integrators,
                       AddIntegratorFn add_integrator);

   void AddIntegratorsAndMarkers(BilinearForm &a_to,
                                 GetIntegratorsFn get_integrators,
                                 GetMarkersFn get_markers,
                                 AddIntegratorMarkersFn add_integrator);

   void ResetIntegrationRules(GetIntegratorsFn get_integrators);

protected:
   /// Adds all the integrators from the member data @a a to the BilinearForm
   /// @a a_to. Marks @a a_to as using external integrators. If the mesh
   /// consists of tensor product elements, temporarily changes the integration
   /// rules of the integrators to use collocated quadrature for better
   /// conditioning of the LOR system.
   void AddIntegrators(BilinearForm &a_to);

   /// Resets the integration rules of the integrators of @a a to their original
   /// values.
   void ResetIntegrationRules();

   LORBase(BilinearForm &a_);
};

/// Create and assemble a low-order refined version of a BilinearForm.
class LOR : LORBase
{
protected:
   Mesh mesh;
   FiniteElementCollection *fec;
   FiniteElementSpace *fes;
   BilinearForm *a;
   SparseMatrix A;

public:
   /// Construct the low-order refined version of @a a_ho using the given list
   /// of essential DOFs. The mesh is refined using the refinement type
   /// specified by @a ref_type (see Mesh::MakeRefined).
   LOR(BilinearForm &a_ho, const Array<int> &ess_tdof_list,
       int ref_type=BasisType::GaussLobatto);

   /// Return the assembled LOR operator as a SparseMatrix
   SparseMatrix &GetAssembledMatrix();

   ~LOR();
};

/// Create a solver of type @a SolverType using the low-order refined version
/// of the given BilinearForm.
template <typename SolverType>
class LORSolver : public Solver
{
protected:
   LOR lor;
   SolverType solver;
public:
   /// Create a solver of type @a SolverType, created using a LOR version of
   /// @a a_ho, see LOR.
   LORSolver(BilinearForm &a_ho, const Array<int> &ess_tdof_list,
             int ref_type=BasisType::GaussLobatto)
      : lor(a_ho, ess_tdof_list, ref_type),
        solver(lor.GetAssembledMatrix())
   { }

   /// Not supported.
   void SetOperator(const Operator &op)
   {
      if (&op != &lor.GetAssembledMatrix())
      {
         MFEM_ABORT("LORSolver::SetOperator not supported.")
      }
   }

   void Mult(const Vector &x, Vector &y) const
   {
      solver.Mult(x, y);
   }

   /// Support the use of -> to call methods of the underlying solver.
   SolverType *operator->() const { return solver; }

   /// Access the underlying solver.
   SolverType &operator*() { return solver; }
};

#ifdef MFEM_USE_MPI

/// Create and assemble a low-order refined version of a ParBilinearForm in
/// parallel.
class ParLOR : public LORBase
{
protected:
   ParMesh mesh;
   FiniteElementCollection *fec;
   ParFiniteElementSpace *fes;
   ParBilinearForm *a;
   HypreParMatrix A;

public:
   /// Construct the low-order refined version of @a a_ho using the given list
   /// of essential DOFs. The mesh is refined using the refinement type
   /// specified by @a ref_type (see ParMesh::MakeRefined).
   ParLOR(ParBilinearForm &a_ho, const Array<int> &ess_tdof_list,
          int ref_type=BasisType::GaussLobatto);

   /// Return the assembled LOR operator as a HypreParMatrix.
   HypreParMatrix &GetAssembledMatrix();

   ~ParLOR();
};

/// Wrapper class for a solver of type @a SolverType constructred using the
/// low-order refined version of the given ParBilinearForm.
template <typename SolverType>
class ParLORSolver : public Solver
{
protected:
   ParLOR lor;
   SolverType solver;
public:
   /// Create a solver of type @a SolverType, created using a LOR version of
   /// @a a_ho, see ParLOR.
   ParLORSolver(ParBilinearForm &a_ho, const Array<int> &ess_tdof_list,
                int ref_type=BasisType::GaussLobatto)
      : lor(a_ho, ess_tdof_list, ref_type),
        solver(lor.GetAssembledMatrix())
   { }

   void SetOperator(const Operator &op)
   {
      if (&op != &lor.GetAssembledMatrix())
      {
         MFEM_ABORT("ParLORSolver::SetOperator not supported.")
      }
   }

   void Mult(const Vector &x, Vector &y) const
   {
      solver.Mult(x, y);
   }

   /// Support the use of -> to call methods of the underlying solver.
   SolverType *operator->() const { return solver; }

   /// Access the underlying solver.
   SolverType &operator*() { return solver; }
};

#endif

} // namespace mfem

#endif
<|endoftext|>


<commit_before>#include "fenetre.h"
#include "ui_fenetre.h"

Fenetre::Fenetre(QWidget *parent) : QMainWindow(parent), ui(new Ui::Fenetre)
{
    ui->setupUi(this);

    //on connecte les Qapplication
    connect(ui->actionNouveau,SIGNAL(triggered()),this,SLOT(nouveauFichier()));
    connect(ui->actionOuvrir,SIGNAL(triggered()),this,SLOT(ouvrirFichier()));
    connect(ui->actionSauvegarder,SIGNAL(triggered()),this,SLOT(sauvegarderFichier()));
    connect(ui->actionQuitter,SIGNAL(triggered()),qApp,SLOT(quit()));
    //connect(ui->)
}

Fenetre::~Fenetre()
{
    delete ui;
}

void Fenetre::nouveauFichier()
{
    //on vide les listes
    ui->MarquesList->clear();
    ui->SceauxList->clear();
    ui->GlyphesList->clear();
    ui->QuintList->clear();

    updateStats();
}

void Fenetre::ouvrirFichier()
{
    //rien pour le moment
}

void Fenetre::sauvegarderFichier()
{
    //rien non plus
}

void Fenetre::updateStats()
{
    if (ui->MarquesList->count() == 0 && ui->SceauxList->count() == 0 && ui->GlyphesList->count() == 0 && ui->QuintList->count() == 0) //les listes sont toutes vides
    {
        ui->StatLabel->setText(""); //on vide le texte
    }
    else
    {
        QString newLabel{""};
        QString tmp{""};
        std::vector<Effet> allEffect = page.getAllEffect(); //on récupère tous les effets de la page !
        for (auto &a : allEffect) //on parcoure tous les effets
        {
            tmp = (a.second > 0) ? "+ " : "- "; //on prend le signe du bonus
            //+/- XX STAT (avec de la coloration et STAT en italique)
            newLabel += "
" + tmp + QString{a.second} + " " + std::string(a.first).c_str() + "
";
        }
        newLabel += ""; //on finit la mise en page
        ui->StatLabel->setText(newLabel);
    }
}
<commit_msg>On met en place pour demain en montrant l'architecture prévue. Il faudra add un header pour la gestion des fichier voir un pour la conversion runes -> Widget. Penser à modifier curseur ! DODO NOW !<commit_after>#include "fenetre.h"
#include "ui_fenetre.h"

Fenetre::Fenetre(QWidget *parent) : QMainWindow(parent), ui(new Ui::Fenetre)
{
    ui->setupUi(this);

    //on connecte les Qapplication
    connect(ui->actionNouveau,SIGNAL(triggered()),this,SLOT(nouveauFichier()));
    connect(ui->actionOuvrir,SIGNAL(triggered()),this,SLOT(ouvrirFichier()));
    connect(ui->actionSauvegarder,SIGNAL(triggered()),this,SLOT(sauvegarderFichier()));
    connect(ui->actionQuitter,SIGNAL(triggered()),qApp,SLOT(quit()));

    index = loadIndexFromFile("runes.index"); //on charge les runes
    std::vector<QListWidgetItem> indexQList = indexToWidget(index); //on les transforme en widgets affichables
    for (auto &a : indexQList)
    {
        ui->DRunelist->addItem(a); //on ajoute les runes à la liste
    }
}

Fenetre::~Fenetre()
{
    delete ui;
}

void Fenetre::nouveauFichier()
{
    //on vide les listes
    ui->MarquesList->clear();
    ui->SceauxList->clear();
    ui->GlyphesList->clear();
    ui->QuintList->clear();

    updateStats();
}

void Fenetre::ouvrirFichier()
{
    //rien pour le moment
}

void Fenetre::sauvegarderFichier()
{
    //rien non plus
}

void Fenetre::updateStats()
{
    if (ui->MarquesList->count() == 0 && ui->SceauxList->count() == 0 && ui->GlyphesList->count() == 0 && ui->QuintList->count() == 0) //les listes sont toutes vides
    {
        ui->StatLabel->setText(""); //on vide le texte
    }
    else
    {
        QString newLabel{""};
        QString tmp{""};
        std::vector<Effet> allEffect = page.getAllEffect(); //on récupère tous les effets de la page !
        for (auto &a : allEffect) //on parcoure tous les effets
        {
            tmp = (a.second > 0) ? "+ " : "- "; //on prend le signe du bonus
            //+/- XX STAT (avec de la coloration et STAT en italique)
            newLabel += "
" + tmp + QString{a.second} + " " + std::string(a.first).c_str() + "
";
        }
        newLabel += ""; //on finit la mise en page
        ui->StatLabel->setText(newLabel);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014, Ford Motor Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Ford Motor Company nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <pthread.h>
#include <unistd.h>
#include <iomanip>

#include <libusb/libusb.h>

#include <sstream>

#include "transport_manager/usb/libusb/usb_connection.h"
#include "transport_manager/transport_adapter/transport_adapter_impl.h"

#include "utils/logger.h"

namespace transport_manager {
namespace transport_adapter {

CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")

UsbConnection::UsbConnection(const DeviceUID& device_uid,
                             const ApplicationHandle& app_handle,
                             TransportAdapterController* controller,
                             const UsbHandlerSptr usb_handler,
                             PlatformUsbDevice* device)
    : device_uid_(device_uid)
    , app_handle_(app_handle)
    , controller_(controller)
    , usb_handler_(usb_handler)
    , libusb_device_(device->GetLibusbDevice())
    , device_handle_(device->GetLibusbHandle())
    , in_endpoint_(0)
    , in_endpoint_max_packet_size_(0)
    , out_endpoint_(0)
    , out_endpoint_max_packet_size_(0)
    , in_buffer_(NULL)
    , in_transfer_(NULL)
    , out_transfer_(0)
    , out_messages_()
    , current_out_message_()
    , bytes_sent_(0)
    , disconnecting_(false)
    , waiting_in_transfer_cancel_(false)
    , waiting_out_transfer_cancel_(false) {}

UsbConnection::~UsbConnection() {
  LOG4CXX_TRACE(logger_, "enter with this" << this);
  Finalise();
  libusb_free_transfer(in_transfer_);
  delete[] in_buffer_;
  LOG4CXX_TRACE(logger_, "exit");
}

// Callback for handling income and outcome data from lib_usb
void InTransferCallback(libusb_transfer* transfer) {
  static_cast<UsbConnection*>(transfer->user_data)->OnInTransfer(transfer);
}

void OutTransferCallback(libusb_transfer* transfer) {
  static_cast<UsbConnection*>(transfer->user_data)->OnOutTransfer(transfer);
}

bool UsbConnection::PostInTransfer() {
  LOG4CXX_TRACE(logger_, "enter");
  libusb_fill_bulk_transfer(in_transfer_,
                            device_handle_,
                            in_endpoint_,
                            in_buffer_,
                            in_endpoint_max_packet_size_,
                            InTransferCallback,
                            this,
                            0);
  const int libusb_ret = libusb_submit_transfer(in_transfer_);
  if (LIBUSB_SUCCESS != libusb_ret) {
    LOG4CXX_ERROR(
        logger_,
        "libusb_submit_transfer failed: " << libusb_error_name(libusb_ret));
    LOG4CXX_TRACE(
        logger_,
        "exit with FALSE. Condition: LIBUSB_SUCCESS != libusb_submit_transfer");
    return false;
  }
  LOG4CXX_TRACE(logger_, "exit with TRUE");
  return true;
}

std::string hex_data(const unsigned char* const buffer,
                     const int actual_length) {
  std::ostringstream hexdata;
  for (int i = 0; i < actual_length; ++i) {
    hexdata << " " << std::hex << std::setw(2) << std::setfill('0')
            << int(buffer[i]);
  }
  return hexdata.str();
}

void UsbConnection::OnInTransfer(libusb_transfer* transfer) {
  LOG4CXX_TRACE(logger_, "enter with Libusb_transfer*: " << transfer);
  if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
    LOG4CXX_DEBUG(logger_,
                  "USB incoming transfer, size:"
                      << transfer->actual_length << ", data:"
                      << hex_data(transfer->buffer, transfer->actual_length));
    ::protocol_handler::RawMessagePtr data(new protocol_handler::RawMessage(
        0, 0, in_buffer_, transfer->actual_length));
    controller_->DataReceiveDone(device_uid_, app_handle_, data);
  } else if(transfer->status == LIBUSB_TRANSFER_STALL){
    AbortConnection();
    return;
  } else {
    LOG4CXX_ERROR(logger_,
                  "USB incoming transfer failed: "
                      << libusb_error_name(transfer->status));
    controller_->DataReceiveFailed(
        device_uid_, app_handle_, DataReceiveError());
  }
  if (disconnecting_) {
    waiting_in_transfer_cancel_ = false;
  } else {
    if (!PostInTransfer()) {
      LOG4CXX_ERROR(logger_,
                    "USB incoming transfer failed with "
                        << "LIBUSB_TRANSFER_NO_DEVICE. Abort connection.");
      AbortConnection();
    }
  }
  LOG4CXX_TRACE(logger_, "exit");
}

void UsbConnection::PopOutMessage() {
  LOG4CXX_TRACE(logger_, "enter");
  bytes_sent_ = 0;
  if (out_messages_.empty()) {
    current_out_message_.reset();
  } else {
    current_out_message_ = out_messages_.front();
    out_messages_.pop_front();
    PostOutTransfer();
  }
  LOG4CXX_TRACE(logger_, "exit");
}

bool UsbConnection::PostOutTransfer() {
  if (disconnecting_) {
    return false;
  }
  LOG4CXX_TRACE(logger_, "enter");
  out_transfer_ = libusb_alloc_transfer(0);
  if (0 == out_transfer_) {
    LOG4CXX_ERROR(logger_, "libusb_alloc_transfer failed");
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: 0 == out_transfer_");
    return false;
  }
  libusb_fill_bulk_transfer(out_transfer_,
                            device_handle_,
                            out_endpoint_,
                            current_out_message_->data() + bytes_sent_,
                            current_out_message_->data_size() - bytes_sent_,
                            OutTransferCallback,
                            this,
                            0);
  const int libusb_ret = libusb_submit_transfer(out_transfer_);
  if (LIBUSB_SUCCESS != libusb_ret) {
    LOG4CXX_ERROR(
        logger_,
        "libusb_submit_transfer failed: " << libusb_error_name(libusb_ret)
                                          << ". Abort connection.");
    AbortConnection();
    LOG4CXX_TRACE(logger_,
                  "exit with FALSE. Condition: "
                      << "LIBUSB_SUCCESS != libusb_fill_bulk_transfer");
    return false;
  }
  LOG4CXX_TRACE(logger_, "exit with TRUE");
  return true;
}

void UsbConnection::OnOutTransfer(libusb_transfer* transfer) {
  if (disconnecting_) {
    return ;
  }
  LOG4CXX_TRACE(logger_, "enter with  Libusb_transfer*: " << transfer);
  sync_primitives::AutoLock locker(out_messages_mutex_);
  if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
    bytes_sent_ += transfer->actual_length;
    if (current_out_message_.valid() && bytes_sent_ == current_out_message_->data_size()) {
      LOG4CXX_DEBUG(
          logger_,
          "USB out transfer, data sent: " << current_out_message_.get());
      controller_->DataSendDone(device_uid_, app_handle_, current_out_message_);
      PopOutMessage();
    }
  } else {
    if (current_out_message_.valid() && bytes_sent_ == current_out_message_->data_size()) {
      LOG4CXX_ERROR(
          logger_,
          "USB out transfer failed: " << libusb_error_name(transfer->status));
      controller_->DataSendFailed(
          device_uid_, app_handle_, current_out_message_, DataSendError());
      PopOutMessage();
    }
  }
  if (!current_out_message_.valid()) {
    libusb_free_transfer(transfer);
    out_transfer_ = NULL;
    waiting_out_transfer_cancel_ = false;
  }
  LOG4CXX_TRACE(logger_, "exit");
}

TransportAdapter::Error UsbConnection::SendData(
    ::protocol_handler::RawMessagePtr message) {
  LOG4CXX_TRACE(logger_, "enter with RawMessagePtr: " << message.get());
  if (disconnecting_) {
    LOG4CXX_TRACE(logger_,
                  "exit with TransportAdapter::BAD_STATE. Condition: "
                      << "disconnecting_");
    return TransportAdapter::BAD_STATE;
  }
  sync_primitives::AutoLock locker(out_messages_mutex_);
  if (current_out_message_.valid()) {
    out_messages_.push_back(message);
  } else {
    current_out_message_ = message;
    if (!PostOutTransfer()) {
      controller_->DataSendFailed(
          device_uid_, app_handle_, message, DataSendError());
      LOG4CXX_TRACE(
          logger_,
          "exit with TransportAdapter::FAIL. Condition: !PostOutTransfer()");
      return TransportAdapter::FAIL;
    }
  }
  LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK.");
  return TransportAdapter::OK;
}

void UsbConnection::Finalise() {
  LOG4CXX_TRACE(logger_, "enter");
  LOG4CXX_DEBUG(logger_, "Finalise USB connection " << device_uid_);
  {
    sync_primitives::AutoLock locker(out_messages_mutex_);
    disconnecting_ = true;
    if (out_transfer_) {
      waiting_out_transfer_cancel_ = true;
      if (LIBUSB_SUCCESS != libusb_cancel_transfer(out_transfer_)) {
        waiting_out_transfer_cancel_ = false;
      }
    }
    if (in_transfer_) {
      waiting_in_transfer_cancel_ = true;
      if (LIBUSB_SUCCESS != libusb_cancel_transfer(in_transfer_)) {
        waiting_in_transfer_cancel_ = false;
      }
    }
    for (std::list<protocol_handler::RawMessagePtr>::iterator it =
             out_messages_.begin();
         it != out_messages_.end();
         it = out_messages_.erase(it)) {
      controller_->DataSendFailed(
          device_uid_, app_handle_, *it, DataSendError());
    }
  }
  while (waiting_in_transfer_cancel_ || waiting_out_transfer_cancel_) {
    if (disconnecting_) {
      break;
    }
    pthread_yield();
  }
  LOG4CXX_TRACE(logger_, "exit");
}

void UsbConnection::AbortConnection() {
  LOG4CXX_TRACE(logger_, "enter");
  controller_->ConnectionAborted(
      device_uid_, app_handle_, CommunicationError());
  Disconnect();
  LOG4CXX_TRACE(logger_, "exit");
}

TransportAdapter::Error UsbConnection::Disconnect() {
  Finalise();
  controller_->DisconnectDone(device_uid_, app_handle_);
  return TransportAdapter::OK;
}

bool UsbConnection::Init() {
  LOG4CXX_TRACE(logger_, "enter");
  if (!FindEndpoints()) {
    LOG4CXX_ERROR(logger_, "EndPoints was not found");
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !FindEndpoints()");
    return false;
  }
  in_buffer_ = new unsigned char[in_endpoint_max_packet_size_];
  in_transfer_ = libusb_alloc_transfer(0);
  if (NULL == in_transfer_) {
    LOG4CXX_ERROR(logger_, "libusb_alloc_transfer failed");
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: NULL == in_transfer_");
    return false;
  }

  controller_->ConnectDone(device_uid_, app_handle_);
  if (!PostInTransfer()) {
    LOG4CXX_ERROR(logger_, "PostInTransfer failed. Call ConnectionAborted");
    controller_->ConnectionAborted(
        device_uid_, app_handle_, CommunicationError());
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !PostInTransfer()");
    return false;
  }

  LOG4CXX_TRACE(logger_, "exit with TRUE");
  return true;
}

bool UsbConnection::FindEndpoints() {
  LOG4CXX_TRACE(logger_, "enter");
  struct libusb_config_descriptor* config;
  const int libusb_ret =
      libusb_get_active_config_descriptor(libusb_device_, &config);
  if (LIBUSB_SUCCESS != libusb_ret) {
    LOG4CXX_ERROR(logger_,
                  "libusb_get_active_config_descriptor failed: "
                      << libusb_error_name(libusb_ret));
    LOG4CXX_TRACE(logger_,
                  "exit with FALSE. Condition: LIBUSB_SUCCESS != libusb_ret");
    return false;
  }

  bool find_in_endpoint = true;
  bool find_out_endpoint = true;

  for (int i = 0; i < config->bNumInterfaces; ++i) {
    const libusb_interface& interface = config->interface[i];
    for (int i = 0; i < interface.num_altsetting; ++i) {
      const libusb_interface_descriptor& iface_desc = interface.altsetting[i];
      for (int i = 0; i < iface_desc.bNumEndpoints; ++i) {
        const libusb_endpoint_descriptor& endpoint_desc =
            iface_desc.endpoint[i];

        const uint8_t endpoint_dir =
            endpoint_desc.bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK;
        if (find_in_endpoint && endpoint_dir == LIBUSB_ENDPOINT_IN) {
          in_endpoint_ = endpoint_desc.bEndpointAddress;
          in_endpoint_max_packet_size_ = endpoint_desc.wMaxPacketSize;
          find_in_endpoint = false;
        } else if (find_out_endpoint && endpoint_dir == LIBUSB_ENDPOINT_OUT) {
          out_endpoint_ = endpoint_desc.bEndpointAddress;
          out_endpoint_max_packet_size_ = endpoint_desc.wMaxPacketSize;
          find_out_endpoint = false;
        }
      }
    }
  }
  libusb_free_config_descriptor(config);

  const bool result = !(find_in_endpoint || find_out_endpoint);
  LOG4CXX_TRACE(logger_, "exit with " << (result ? "TRUE" : "FALSE"));
  return result;
}
}  // namespace transport_adapter
}  // namespace transport_manager
<commit_msg>Fix App exception disconnect<commit_after>/*
 * Copyright (c) 2013-2014, Ford Motor Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Ford Motor Company nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <pthread.h>
#include <unistd.h>
#include <iomanip>

#include <libusb/libusb.h>

#include <sstream>

#include "transport_manager/usb/libusb/usb_connection.h"
#include "transport_manager/transport_adapter/transport_adapter_impl.h"

#include "utils/logger.h"

namespace transport_manager {
namespace transport_adapter {

CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")

UsbConnection::UsbConnection(const DeviceUID& device_uid,
                             const ApplicationHandle& app_handle,
                             TransportAdapterController* controller,
                             const UsbHandlerSptr usb_handler,
                             PlatformUsbDevice* device)
    : device_uid_(device_uid)
    , app_handle_(app_handle)
    , controller_(controller)
    , usb_handler_(usb_handler)
    , libusb_device_(device->GetLibusbDevice())
    , device_handle_(device->GetLibusbHandle())
    , in_endpoint_(0)
    , in_endpoint_max_packet_size_(0)
    , out_endpoint_(0)
    , out_endpoint_max_packet_size_(0)
    , in_buffer_(NULL)
    , in_transfer_(NULL)
    , out_transfer_(0)
    , out_messages_()
    , current_out_message_()
    , bytes_sent_(0)
    , disconnecting_(false)
    , waiting_in_transfer_cancel_(false)
    , waiting_out_transfer_cancel_(false) {}

UsbConnection::~UsbConnection() {
  LOG4CXX_TRACE(logger_, "enter with this" << this);
  Finalise();
  libusb_free_transfer(in_transfer_);
  delete[] in_buffer_;
  LOG4CXX_TRACE(logger_, "exit");
}

// Callback for handling income and outcome data from lib_usb
void InTransferCallback(libusb_transfer* transfer) {
  static_cast<UsbConnection*>(transfer->user_data)->OnInTransfer(transfer);
}

void OutTransferCallback(libusb_transfer* transfer) {
  static_cast<UsbConnection*>(transfer->user_data)->OnOutTransfer(transfer);
}

bool UsbConnection::PostInTransfer() {
  LOG4CXX_TRACE(logger_, "enter");
  libusb_fill_bulk_transfer(in_transfer_,
                            device_handle_,
                            in_endpoint_,
                            in_buffer_,
                            in_endpoint_max_packet_size_,
                            InTransferCallback,
                            this,
                            0);
  const int libusb_ret = libusb_submit_transfer(in_transfer_);
  if (LIBUSB_SUCCESS != libusb_ret) {
    LOG4CXX_ERROR(
        logger_,
        "libusb_submit_transfer failed: " << libusb_error_name(libusb_ret));
    LOG4CXX_TRACE(
        logger_,
        "exit with FALSE. Condition: LIBUSB_SUCCESS != libusb_submit_transfer");
    return false;
  }
  LOG4CXX_TRACE(logger_, "exit with TRUE");
  return true;
}

std::string hex_data(const unsigned char* const buffer,
                     const int actual_length) {
  std::ostringstream hexdata;
  for (int i = 0; i < actual_length; ++i) {
    hexdata << " " << std::hex << std::setw(2) << std::setfill('0')
            << int(buffer[i]);
  }
  return hexdata.str();
}

void UsbConnection::OnInTransfer(libusb_transfer* transfer) {
  LOG4CXX_TRACE(logger_, "enter with Libusb_transfer*: " << transfer);
  if (transfer->status == LIBUSB_TRANSFER_COMPLETED && transfer->actual_length > 0) {
    LOG4CXX_DEBUG(logger_,
                  "USB incoming transfer, size:"
                      << transfer->actual_length << ", data:"
                      << hex_data(transfer->buffer, transfer->actual_length));
    ::protocol_handler::RawMessagePtr data(new protocol_handler::RawMessage(
        0, 0, in_buffer_, transfer->actual_length));
    controller_->DataReceiveDone(device_uid_, app_handle_, data);
  } else if(transfer->status == LIBUSB_TRANSFER_STALL){
    AbortConnection();
    return;
  } else {
    LOG4CXX_ERROR(logger_,
                  "USB incoming transfer failed: "
                      << libusb_error_name(transfer->status));
    controller_->DataReceiveFailed(
        device_uid_, app_handle_, DataReceiveError());
  }
  if (disconnecting_) {
    waiting_in_transfer_cancel_ = false;
  } else {
    if (!PostInTransfer()) {
      LOG4CXX_ERROR(logger_,
                    "USB incoming transfer failed with "
                        << "LIBUSB_TRANSFER_NO_DEVICE. Abort connection.");
      AbortConnection();
    }
  }
  LOG4CXX_TRACE(logger_, "exit");
}

void UsbConnection::PopOutMessage() {
  LOG4CXX_TRACE(logger_, "enter");
  bytes_sent_ = 0;
  if (out_messages_.empty()) {
    current_out_message_.reset();
  } else {
    current_out_message_ = out_messages_.front();
    out_messages_.pop_front();
    PostOutTransfer();
  }
  LOG4CXX_TRACE(logger_, "exit");
}

bool UsbConnection::PostOutTransfer() {
  if (disconnecting_) {
    return false;
  }
  LOG4CXX_TRACE(logger_, "enter");
  out_transfer_ = libusb_alloc_transfer(0);
  if (0 == out_transfer_) {
    LOG4CXX_ERROR(logger_, "libusb_alloc_transfer failed");
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: 0 == out_transfer_");
    return false;
  }
  libusb_fill_bulk_transfer(out_transfer_,
                            device_handle_,
                            out_endpoint_,
                            current_out_message_->data() + bytes_sent_,
                            current_out_message_->data_size() - bytes_sent_,
                            OutTransferCallback,
                            this,
                            0);
  const int libusb_ret = libusb_submit_transfer(out_transfer_);
  if (LIBUSB_SUCCESS != libusb_ret) {
    LOG4CXX_ERROR(
        logger_,
        "libusb_submit_transfer failed: " << libusb_error_name(libusb_ret)
                                          << ". Abort connection.");
    AbortConnection();
    LOG4CXX_TRACE(logger_,
                  "exit with FALSE. Condition: "
                      << "LIBUSB_SUCCESS != libusb_fill_bulk_transfer");
    return false;
  }
  LOG4CXX_TRACE(logger_, "exit with TRUE");
  return true;
}

void UsbConnection::OnOutTransfer(libusb_transfer* transfer) {
  if (disconnecting_) {
    return ;
  }
  LOG4CXX_TRACE(logger_, "enter with  Libusb_transfer*: " << transfer);
  sync_primitives::AutoLock locker(out_messages_mutex_);
  if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
    bytes_sent_ += transfer->actual_length;
    if (current_out_message_.valid() && bytes_sent_ == current_out_message_->data_size()) {
      LOG4CXX_DEBUG(
          logger_,
          "USB out transfer, data sent: " << current_out_message_.get());
      controller_->DataSendDone(device_uid_, app_handle_, current_out_message_);
      PopOutMessage();
    }
  } else {
    if (current_out_message_.valid() && bytes_sent_ == current_out_message_->data_size()) {
      LOG4CXX_ERROR(
          logger_,
          "USB out transfer failed: " << libusb_error_name(transfer->status));
      controller_->DataSendFailed(
          device_uid_, app_handle_, current_out_message_, DataSendError());
      PopOutMessage();
    }
  }
  if (!current_out_message_.valid()) {
    libusb_free_transfer(transfer);
    out_transfer_ = NULL;
    waiting_out_transfer_cancel_ = false;
  }
  LOG4CXX_TRACE(logger_, "exit");
}

TransportAdapter::Error UsbConnection::SendData(
    ::protocol_handler::RawMessagePtr message) {
  LOG4CXX_TRACE(logger_, "enter with RawMessagePtr: " << message.get());
  if (disconnecting_) {
    LOG4CXX_TRACE(logger_,
                  "exit with TransportAdapter::BAD_STATE. Condition: "
                      << "disconnecting_");
    return TransportAdapter::BAD_STATE;
  }
  sync_primitives::AutoLock locker(out_messages_mutex_);
  if (current_out_message_.valid()) {
    out_messages_.push_back(message);
  } else {
    current_out_message_ = message;
    if (!PostOutTransfer()) {
      controller_->DataSendFailed(
          device_uid_, app_handle_, message, DataSendError());
      LOG4CXX_TRACE(
          logger_,
          "exit with TransportAdapter::FAIL. Condition: !PostOutTransfer()");
      return TransportAdapter::FAIL;
    }
  }
  LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK.");
  return TransportAdapter::OK;
}

void UsbConnection::Finalise() {
  LOG4CXX_TRACE(logger_, "enter");
  LOG4CXX_DEBUG(logger_, "Finalise USB connection " << device_uid_);
  {
    sync_primitives::AutoLock locker(out_messages_mutex_);
    disconnecting_ = true;
    if (out_transfer_) {
      waiting_out_transfer_cancel_ = true;
      if (LIBUSB_SUCCESS != libusb_cancel_transfer(out_transfer_)) {
        waiting_out_transfer_cancel_ = false;
      }
    }
    if (in_transfer_) {
      waiting_in_transfer_cancel_ = true;
      if (LIBUSB_SUCCESS != libusb_cancel_transfer(in_transfer_)) {
        waiting_in_transfer_cancel_ = false;
      }
    }
    for (std::list<protocol_handler::RawMessagePtr>::iterator it =
             out_messages_.begin();
         it != out_messages_.end();
         it = out_messages_.erase(it)) {
      controller_->DataSendFailed(
          device_uid_, app_handle_, *it, DataSendError());
    }
  }
  while (waiting_in_transfer_cancel_ || waiting_out_transfer_cancel_) {
    if (disconnecting_) {
      break;
    }
    pthread_yield();
  }
  LOG4CXX_TRACE(logger_, "exit");
}

void UsbConnection::AbortConnection() {
  LOG4CXX_TRACE(logger_, "enter");
  controller_->ConnectionAborted(
      device_uid_, app_handle_, CommunicationError());
  Disconnect();
  LOG4CXX_TRACE(logger_, "exit");
}

TransportAdapter::Error UsbConnection::Disconnect() {
  Finalise();
  controller_->DisconnectDone(device_uid_, app_handle_);
  return TransportAdapter::OK;
}

bool UsbConnection::Init() {
  LOG4CXX_TRACE(logger_, "enter");
  if (!FindEndpoints()) {
    LOG4CXX_ERROR(logger_, "EndPoints was not found");
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !FindEndpoints()");
    return false;
  }
  in_buffer_ = new unsigned char[in_endpoint_max_packet_size_];
  in_transfer_ = libusb_alloc_transfer(0);
  if (NULL == in_transfer_) {
    LOG4CXX_ERROR(logger_, "libusb_alloc_transfer failed");
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: NULL == in_transfer_");
    return false;
  }

  controller_->ConnectDone(device_uid_, app_handle_);
  if (!PostInTransfer()) {
    LOG4CXX_ERROR(logger_, "PostInTransfer failed. Call ConnectionAborted");
    controller_->ConnectionAborted(
        device_uid_, app_handle_, CommunicationError());
    LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !PostInTransfer()");
    return false;
  }

  LOG4CXX_TRACE(logger_, "exit with TRUE");
  return true;
}

bool UsbConnection::FindEndpoints() {
  LOG4CXX_TRACE(logger_, "enter");
  struct libusb_config_descriptor* config;
  const int libusb_ret =
      libusb_get_active_config_descriptor(libusb_device_, &config);
  if (LIBUSB_SUCCESS != libusb_ret) {
    LOG4CXX_ERROR(logger_,
                  "libusb_get_active_config_descriptor failed: "
                      << libusb_error_name(libusb_ret));
    LOG4CXX_TRACE(logger_,
                  "exit with FALSE. Condition: LIBUSB_SUCCESS != libusb_ret");
    return false;
  }

  bool find_in_endpoint = true;
  bool find_out_endpoint = true;

  for (int i = 0; i < config->bNumInterfaces; ++i) {
    const libusb_interface& interface = config->interface[i];
    for (int i = 0; i < interface.num_altsetting; ++i) {
      const libusb_interface_descriptor& iface_desc = interface.altsetting[i];
      for (int i = 0; i < iface_desc.bNumEndpoints; ++i) {
        const libusb_endpoint_descriptor& endpoint_desc =
            iface_desc.endpoint[i];

        const uint8_t endpoint_dir =
            endpoint_desc.bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK;
        if (find_in_endpoint && endpoint_dir == LIBUSB_ENDPOINT_IN) {
          in_endpoint_ = endpoint_desc.bEndpointAddress;
          in_endpoint_max_packet_size_ = endpoint_desc.wMaxPacketSize;
          find_in_endpoint = false;
        } else if (find_out_endpoint && endpoint_dir == LIBUSB_ENDPOINT_OUT) {
          out_endpoint_ = endpoint_desc.bEndpointAddress;
          out_endpoint_max_packet_size_ = endpoint_desc.wMaxPacketSize;
          find_out_endpoint = false;
        }
      }
    }
  }
  libusb_free_config_descriptor(config);

  const bool result = !(find_in_endpoint || find_out_endpoint);
  LOG4CXX_TRACE(logger_, "exit with " << (result ? "TRUE" : "FALSE"));
  return result;
}
}  // namespace transport_adapter
}  // namespace transport_manager
<|endoftext|>