<commit_before>//
// Shader.cpp for  in /home/massora/GIT/amd_project/render/ShaderTool
//
// Made by dorian pinaud
// Login   <pinaud_d@epitech.net>
//
// Started on  Mon Aug  5 00:37:46 2013 dorian pinaud
// Last update Mon Aug 19 00:15:12 2013 dorian pinaud
//

#include "Utils/OpenGL.hh"

#include "Shader.hh"
#include <assert.h>

namespace OpenGLTools
{

Shader::Shader(void) :
	_vertexId(0),
	_fragId(0),
	_geometryId(0),
	_targets(nullptr),
	_textureNumber(0)
{
}

Shader::~Shader(void)
{
	if (_targets)
		delete _targets;
}

bool Shader::init(std::string const &vertex, std::string const &fragment, std::string const &geometry)
{
  if ((_vertexId = addShader(vertex, GL_VERTEX_SHADER)) == 0)
    {
      std::cerr << "Error: vertex shader invalid" << std::endl;
      return (false);
    }
  if ((_fragId = addShader(fragment, GL_FRAGMENT_SHADER)) == 0)
    {
      std::cerr << "Error: fragment shader invalid" << std::endl;
      return (false);
    }
  if (geometry.empty() == false &&
	  (_geometryId = addShader(geometry, GL_GEOMETRY_SHADER)) == 0)
    {
      std::cerr << "Error: geometry shader invalid" << std::endl;
      return (false);
    }
  _progId = glCreateProgram();
  glAttachShader(_progId, _vertexId);
  glAttachShader(_progId, _fragId);
  if (_geometryId != 0)
	  glAttachShader(_progId, _geometryId);
  linkProgram();

  glDetachShader(_progId, _vertexId);
  glDetachShader(_progId, _fragId);
  if (_geometryId != 0)
	  glDetachShader(_progId, _geometryId);
  glDeleteShader(_vertexId);
  glDeleteShader(_fragId);
  if (_geometryId != 0)
	  glDeleteShader(_geometryId);

  return (true);
}

GLenum  *Shader::getTargets() const
{
	return _targets;
}

unsigned int Shader::getTargetsNumber() const
{
	return _targetsList.size();
}

bool Shader::_build()
{
	use();

	// if there is no targets defined
	if (_targetsList.size() == 0)
	{
		std::cout << "No targets defined for shader" << std::endl;
		_targetsList.insert(GL_COLOR_ATTACHMENT0);
	}

	if (_targets)
		delete _targets;
	_targets = new GLenum[_targetsList.size()];
	if (!_targets)
		return false;

	unsigned int i = 0;
	for (auto &e : _targetsList)
	{
#pragma warning(suppress: 6386)
		_targets[i] = static_cast<GLenum>(e);
		++i;
	}

	unsigned int destIndex = 0;
	for (auto &e : _layersList)
	{
		GLuint	location = glGetUniformLocation(_progId, std::string("layer" + std::to_string(destIndex)).c_str());

		glUniform1i(location, destIndex);
		if (glGetError() != GL_NO_ERROR)
			std::cerr << "Bind active texture failed for uniform <layer" << e << ">." << std::endl;
		++destIndex;
	}

	for (unsigned int i = 0; i < _textureNumber; ++i)
	{
		GLuint	location = glGetUniformLocation(_progId, std::string("fTexture" + std::to_string(i)).c_str());

		glUniform1i(location, i);
		if (glGetError() != GL_NO_ERROR)
			std::cerr << "Bind active texture failed for uniform <fTexture" << i << ">." << std::endl;
		++destIndex;
	}

	return true;
}

	Shader &Shader::addTarget(GLenum target)
	{
		_targetsList.insert(target);
		return *this;
	}

	Shader &Shader::removeTarget(GLenum target)
	{
		_targetsList.erase(target);
		return *this;
	}

	void Shader::clearTargets()
	{
		_targetsList.clear();
		if (_targets)
			delete _targets;
	}

	Shader &Shader::addLayer(GLenum layer)
	{
		_layersList.insert(layer);
		return *this;
	}

	Shader &Shader::removeLayer(GLenum layer)
	{
		_layersList.erase(layer);
		return *this;
	}

	void Shader::clearLayers()
	{
		_layersList.clear();
	}

}<commit_msg>Shader code correction<commit_after>//
// Shader.cpp for  in /home/massora/GIT/amd_project/render/ShaderTool
//
// Made by dorian pinaud
// Login   <pinaud_d@epitech.net>
//
// Started on  Mon Aug  5 00:37:46 2013 dorian pinaud
// Last update Mon Aug 19 00:15:12 2013 dorian pinaud
//

#include "Utils/OpenGL.hh"

#include "Shader.hh"
#include <assert.h>

namespace OpenGLTools
{

Shader::Shader(void) :
	_vertexId(0),
	_fragId(0),
	_geometryId(0),
	_targets(nullptr),
	_textureNumber(0)
{
}

Shader::~Shader(void)
{
	if (_targets)
		delete _targets;
}

bool Shader::init(std::string const &vertex, std::string const &fragment, std::string const &geometry)
{
  if ((_vertexId = addShader(vertex, GL_VERTEX_SHADER)) == 0)
    {
      std::cerr << "Error: vertex shader invalid" << std::endl;
      return (false);
    }
  if ((_fragId = addShader(fragment, GL_FRAGMENT_SHADER)) == 0)
    {
      std::cerr << "Error: fragment shader invalid" << std::endl;
      return (false);
    }
  if (geometry.empty() == false &&
	  (_geometryId = addShader(geometry, GL_GEOMETRY_SHADER)) == 0)
    {
      std::cerr << "Error: geometry shader invalid" << std::endl;
      return (false);
    }
  _progId = glCreateProgram();
  glAttachShader(_progId, _vertexId);
  glAttachShader(_progId, _fragId);
  if (_geometryId != 0)
	  glAttachShader(_progId, _geometryId);
  linkProgram();

  glDetachShader(_progId, _vertexId);
  glDetachShader(_progId, _fragId);
  if (_geometryId != 0)
	  glDetachShader(_progId, _geometryId);
  glDeleteShader(_vertexId);
  glDeleteShader(_fragId);
  if (_geometryId != 0)
	  glDeleteShader(_geometryId);

  return (true);
}

GLenum  *Shader::getTargets() const
{
	return _targets;
}

unsigned int Shader::getTargetsNumber() const
{
	return _targetsList.size();
}

bool Shader::_build()
{
	use();

	// if there is no targets defined
	if (_targetsList.size() == 0)
	{
		std::cout << "No targets defined for shader" << std::endl;
		_targetsList.insert(GL_COLOR_ATTACHMENT0);
	}

	if (_targets)
		delete _targets;
	_targets = new GLenum[_targetsList.size()];
	if (!_targets)
		return false;

	unsigned int i = 0;
	for (auto &e : _targetsList)
	{
#pragma warning(suppress: 6386)
		_targets[i] = static_cast<GLenum>(e);
		++i;
	}

	unsigned int destIndex = 0;
	for (auto &e : _layersList)
	{
		GLuint	location = glGetUniformLocation(_progId, std::string("layer" + std::to_string(destIndex)).c_str());

		glUniform1i(location, destIndex);
		if (glGetError() != GL_NO_ERROR)
			std::cerr << "Bind active texture failed for uniform <layer" << e << ">." << std::endl;
		++destIndex;
	}

	for (unsigned int it = 0; it < _textureNumber; ++it)
	{
		GLuint	location = glGetUniformLocation(_progId, std::string("fTexture" + std::to_string(it)).c_str());

		glUniform1i(location, it);
		if (glGetError() != GL_NO_ERROR)
			std::cerr << "Bind active texture failed for uniform <fTexture" << it << ">." << std::endl;
		++destIndex;
	}

	return true;
}

	Shader &Shader::addTarget(GLenum target)
	{
		_targetsList.insert(target);
		return *this;
	}

	Shader &Shader::removeTarget(GLenum target)
	{
		_targetsList.erase(target);
		return *this;
	}

	void Shader::clearTargets()
	{
		_targetsList.clear();
		if (_targets)
			delete _targets;
	}

	Shader &Shader::addLayer(GLenum layer)
	{
		_layersList.insert(layer);
		return *this;
	}

	Shader &Shader::removeLayer(GLenum layer)
	{
		_layersList.erase(layer);
		return *this;
	}

	void Shader::clearLayers()
	{
		_layersList.clear();
	}

}<|endoftext|>


<commit_before>/*-----------------------------------------------------------------------------
 This source file is part of Hopsan NG

 Copyright (c) 2011
    Mikael Axin, Robert Braun, Alessandro Dell'Amico, Björn Eriksson,
    Peter Nordin, Karl Pettersson, Petter Krus, Ingo Staack

 This file is provided "as is", with no guarantee or warranty for the
 functionality or reliability of the contents. All contents in this file is
 the original work of the copyright holders at the Division of Fluid and
 Mechatronic Systems (Flumes) at Linköping University. Modifying, using or
 redistributing any part of this file is prohibited without explicit
 permission from the copyright holders.
-----------------------------------------------------------------------------*/

//!
//! @file   GUIComponent.cpp
//! @author Flumes <flumes@lists.iei.liu.se>
//! @date   2010-01-01
//!
//! @brief Contains the GUI class representing Components
//!
//$Id$

#include <QDrag>

#include "GUIComponent.h"
#include "GUIContainerObject.h"
#include "Dialogs/ComponentPropertiesDialog.h"
#include "GUIPort.h"
#include "Widgets/ProjectTabWidget.h"
#include "GraphicsView.h"

GUIComponent::GUIComponent(QPointF position, qreal rotation, GUIModelObjectAppearance* pAppearanceData, GUIContainerObject *pParentContainer, selectionStatus startSelected, graphicsType gfxType)
    : GUIModelObject(position, rotation, pAppearanceData, startSelected, gfxType, pParentContainer, pParentContainer)
{
    //Set the hmf save tag name
    mHmfTagName = HMF_COMPONENTTAG;

    //Create the object in core, and get its default core name
    mGUIModelObjectAppearance.setName(mpParentContainerObject->getCoreSystemAccessPtr()->createComponent(mGUIModelObjectAppearance.getTypeName(), mGUIModelObjectAppearance.getName()));

    //Sets the ports
    createPorts();

    refreshDisplayName(); //Make sure name window is correct size for center positioning

    //Component shall be hidden when toggle signals is deactivated, if it is of signal type and has no power ports (= is a sensor)
    if(this->getTypeCQS() == "S" && !this->hasPowerPorts())
    {
        connect(gpMainWindow->mpToggleSignalsAction, SIGNAL(toggled(bool)), this, SLOT(setVisible(bool)));
    }

    QStringList defaultParameterNames = getParameterNames();
    for(int i=0; i<defaultParameterNames.size(); ++i)
    {
        mDefaultParameters.insert(defaultParameterNames.at(i), getParameterValue(defaultParameterNames.at(i)));
    }
}

GUIComponent::~GUIComponent()
{
    //Remove in core
    //! @todo maybe change to delte instead of remove with dodelete yes
    mpParentContainerObject->getCoreSystemAccessPtr()->removeSubComponent(this->getName(), true);
}

//! @brief Returns whether or not the component has at least one power port
bool GUIComponent::hasPowerPorts()
{
    bool retval = false;
    for(int i=0; i<mPortListPtrs.size(); ++i)
    {
        if(mPortListPtrs.at(i)->getNodeType() != "NodeSignal")
        {
            retval = true;
        }
    }
    return retval;
}

//! Event when double clicking on component icon.
void GUIComponent::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    if(!mpParentContainerObject->mpParentProjectTab->isEditingEnabled())
        return;

    QGraphicsWidget::mouseDoubleClickEvent(event);
    //std::cout << "GUIComponent.cpp: " << "mouseDoubleClickEvent " << std::endl;

    //If this is a sink component that has plot data, plot it instead of showing the dialog
    if(this->getTypeName() == "SignalSink" && this->getPort("in")->isConnected() && this->mpParentContainerObject->getAllPlotData().size() > 0)   //Not very nice code, but a nice feature...
    {
        PlotWindow *pPlotWindow = getPort("in")->getConnectedPorts().first()->plot("Value");
        for(int i=1; (i<getPort("in")->getConnectedPorts().size() && pPlotWindow != 0); ++i)
        {
            if(!pPlotWindow)
            {
                pPlotWindow = getPort("in")->getConnectedPorts().at(i)->plot("Value");
            }
            else
            {
                getPort("in")->getConnectedPorts().at(i)->plotToPlotWindow(pPlotWindow, "Value");
            }
        }
        if(!pPlotWindow)
        {
            openPropertiesDialog();
        }
    }
    else
        openPropertiesDialog();
}

//! Returns a string with the component type.
QString GUIComponent::getTypeName()
{
    return mGUIModelObjectAppearance.getTypeName();
}

QString GUIComponent::getTypeCQS()
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getSubComponentTypeCQS(this->getName());
}

void GUIComponent::getParameters(QVector<QString> &qParameterNames, QVector<QString> &qParameterValues, QVector<QString> &qDescriptions, QVector<QString> &qUnits, QVector<QString> &qTypes)
{
    mpParentContainerObject->getCoreSystemAccessPtr()->getParameters(this->getName(), qParameterNames, qParameterValues, qDescriptions, qUnits, qTypes);
}

//! @brief Get a vector with the names of the available parameters
QStringList GUIComponent::getParameterNames()
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterNames(this->getName());
}

QString GUIComponent::getParameterUnit(QString name)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterUnit(this->getName(), name);
}

QString GUIComponent::getParameterDescription(QString name)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterDescription(this->getName(), name);
}

QString GUIComponent::getParameterValue(QString name)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterValue(this->getName(), name);
}

//QString GUIComponent::getParameterValueTxt(QString name)
//{
//    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterValueTxt(this->getName(), name);
//}

//! @brief Set a parameter value to be mapped to a System parameter
bool GUIComponent::setParameterValue(QString name, QString sysParName, bool force)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->setParameter(this->getName(), name, sysParName, force);
}

//! @brief Set a start value to be mapped to a System parameter
bool GUIComponent::setStartValue(QString portName, QString variable, QString sysParName)
{
    QVector<QString> vVariable;
    QVector<QString> vSysParName;
    vVariable.append(variable);
    vSysParName.append(sysParName);
    return this->getPort(portName)->setStartValueDataByNames(vVariable, vSysParName);
}

//! @brief Set a start value to be mapped to a System parameter
QString GUIComponent::getStartValueTxt(QString portName, QString variable)
{
    QVector<QString> vVariable, vSysParName, vUnit;
    this->getPort(portName)->getStartValueDataNamesValuesAndUnits(vVariable, vSysParName, vUnit);
    int idx = vVariable.indexOf(variable);
    if(idx < 0)
        return "";
    else
        return vSysParName[idx];
}

//! @brief Slot that opens the parameter dialog for the component
void GUIComponent::openPropertiesDialog()
{
    ComponentPropertiesDialog *pDialog = new ComponentPropertiesDialog(this, gpMainWindow);
    pDialog->exec();
    delete pDialog;
}

//! @brief Help function to create ports in the component when it is created
void GUIComponent::createPorts()
{
    //! @todo make sure that all old ports and connections are cleared, (not really necessary in guicomponents)
    QString cqsType = mpParentContainerObject->getCoreSystemAccessPtr()->getSubComponentTypeCQS(getName());
    PortAppearanceMapT::iterator i;
    for (i = mGUIModelObjectAppearance.getPortAppearanceMap().begin(); i != mGUIModelObjectAppearance.getPortAppearanceMap().end(); ++i)
    {
        QString nodeType = mpParentContainerObject->getCoreSystemAccessPtr()->getNodeType(this->getName(), i.key());
        QString portType = mpParentContainerObject->getCoreSystemAccessPtr()->getPortType(this->getName(), i.key());
        i.value().selectPortIcon(cqsType, portType, nodeType);

        qreal x = i.value().x * this->boundingRect().width();
        qreal y = i.value().y * this->boundingRect().height();

        GUIPort *pNewPort = new GUIPort(i.key(), x, y, &(i.value()), this);
        mPortListPtrs.append(pNewPort);
    }
}

int GUIComponent::type() const
{
    return Type;
}

QString GUIComponent::getDefaultParameter(QString name)
{
    if(mDefaultParameters.contains(name))
        return mDefaultParameters.find(name).value();
    else
        return QString();
}

void GUIComponent::setVisible(bool visible)
{
    this->mpIcon->setVisible(visible);
}

//! @brief Save component coredata to XML Dom Element
//! @param[in] rDomElement The dom element to save to
void GUIComponent::saveCoreDataToDomElement(QDomElement &rDomElement)
{
    GUIModelObject::saveCoreDataToDomElement(rDomElement);

    //Save parameters (also core related)
    QDomElement xmlParameters = appendDomElement(rDomElement, HMF_PARAMETERS);
    //! @todo need more efficient fetching of both par names and values in one call to avoid re-searching every time
    QVector<QString> parameterNames, parameterValues, descriptions, units, types;
    getParameters(parameterNames, parameterValues, descriptions, units, types);
    QVector<QString>::iterator pit;
    for(pit = parameterNames.begin(); pit != parameterNames.end(); ++pit)
    {
        QDomElement xmlParam = appendDomElement(xmlParameters, HMF_PARAMETERTAG);
        xmlParam.setAttribute(HMF_NAMETAG, *pit);
        xmlParam.setAttribute(HMF_VALUETAG, mpParentContainerObject->getCoreSystemAccessPtr()->getParameterValue(this->getName(), (*pit)));
        /*if(this->isParameterMappedToSystemParameter(*pit))
        {
            xmlParam.setAttribute(HMF_SYSTEMPARAMETERTAG, this->getSystemParameterKey(*pit));
        }*/
    }

    //Save start values //Is not needed, start values are saved as ordinary parameters! This code snippet can probably be removed.
//    QDomElement xmlStartValues = appendDomElement(rDomElement, HMF_STARTVALUES);
//    QVector<QString> startValueNames;
//    QVector<QString> startValueValuesTxt;
//    QVector<QString> dummy;
//    QList<GUIPort*>::iterator portIt;
//    for(portIt = mPortListPtrs.begin(); portIt != mPortListPtrs.end(); ++portIt)
//    {
//        mpParentContainerObject->getCoreSystemAccessPtr()->getStartValueDataNamesValuesAndUnits(this->getName(), (*portIt)->getPortName(), startValueNames, startValueValuesTxt, dummy);
//        if((!startValueNames.empty()))
//        {
//            for(int i = 0; i < startValueNames.size(); ++i)
//            {
//                QDomElement xmlStartValue = appendDomElement(xmlStartValues, "startvalue");
//                xmlStartValue.setAttribute("portname", (*portIt)->getPortName());
//                xmlStartValue.setAttribute("variable", startValueNames[i]);
//                xmlStartValue.setAttribute("value", startValueValuesTxt[i]);
//            }
//        }
//    }
}
<commit_msg>changes due to removed of  GUIPort::setStartValueDataByNames, should not be used anymore<commit_after>/*-----------------------------------------------------------------------------
 This source file is part of Hopsan NG

 Copyright (c) 2011
    Mikael Axin, Robert Braun, Alessandro Dell'Amico, Björn Eriksson,
    Peter Nordin, Karl Pettersson, Petter Krus, Ingo Staack

 This file is provided "as is", with no guarantee or warranty for the
 functionality or reliability of the contents. All contents in this file is
 the original work of the copyright holders at the Division of Fluid and
 Mechatronic Systems (Flumes) at Linköping University. Modifying, using or
 redistributing any part of this file is prohibited without explicit
 permission from the copyright holders.
-----------------------------------------------------------------------------*/

//!
//! @file   GUIComponent.cpp
//! @author Flumes <flumes@lists.iei.liu.se>
//! @date   2010-01-01
//!
//! @brief Contains the GUI class representing Components
//!
//$Id$

#include <QDrag>

#include "GUIComponent.h"
#include "GUIContainerObject.h"
#include "Dialogs/ComponentPropertiesDialog.h"
#include "GUIPort.h"
#include "Widgets/ProjectTabWidget.h"
#include "GraphicsView.h"

GUIComponent::GUIComponent(QPointF position, qreal rotation, GUIModelObjectAppearance* pAppearanceData, GUIContainerObject *pParentContainer, selectionStatus startSelected, graphicsType gfxType)
    : GUIModelObject(position, rotation, pAppearanceData, startSelected, gfxType, pParentContainer, pParentContainer)
{
    //Set the hmf save tag name
    mHmfTagName = HMF_COMPONENTTAG;

    //Create the object in core, and get its default core name
    mGUIModelObjectAppearance.setName(mpParentContainerObject->getCoreSystemAccessPtr()->createComponent(mGUIModelObjectAppearance.getTypeName(), mGUIModelObjectAppearance.getName()));

    //Sets the ports
    createPorts();

    refreshDisplayName(); //Make sure name window is correct size for center positioning

    //Component shall be hidden when toggle signals is deactivated, if it is of signal type and has no power ports (= is a sensor)
    if(this->getTypeCQS() == "S" && !this->hasPowerPorts())
    {
        connect(gpMainWindow->mpToggleSignalsAction, SIGNAL(toggled(bool)), this, SLOT(setVisible(bool)));
    }

    QStringList defaultParameterNames = getParameterNames();
    for(int i=0; i<defaultParameterNames.size(); ++i)
    {
        mDefaultParameters.insert(defaultParameterNames.at(i), getParameterValue(defaultParameterNames.at(i)));
    }
}

GUIComponent::~GUIComponent()
{
    //Remove in core
    //! @todo maybe change to delte instead of remove with dodelete yes
    mpParentContainerObject->getCoreSystemAccessPtr()->removeSubComponent(this->getName(), true);
}

//! @brief Returns whether or not the component has at least one power port
bool GUIComponent::hasPowerPorts()
{
    bool retval = false;
    for(int i=0; i<mPortListPtrs.size(); ++i)
    {
        if(mPortListPtrs.at(i)->getNodeType() != "NodeSignal")
        {
            retval = true;
        }
    }
    return retval;
}

//! Event when double clicking on component icon.
void GUIComponent::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    if(!mpParentContainerObject->mpParentProjectTab->isEditingEnabled())
        return;

    QGraphicsWidget::mouseDoubleClickEvent(event);
    //std::cout << "GUIComponent.cpp: " << "mouseDoubleClickEvent " << std::endl;

    //If this is a sink component that has plot data, plot it instead of showing the dialog
    if(this->getTypeName() == "SignalSink" && this->getPort("in")->isConnected() && this->mpParentContainerObject->getAllPlotData().size() > 0)   //Not very nice code, but a nice feature...
    {
        PlotWindow *pPlotWindow = getPort("in")->getConnectedPorts().first()->plot("Value");
        for(int i=1; (i<getPort("in")->getConnectedPorts().size() && pPlotWindow != 0); ++i)
        {
            if(!pPlotWindow)
            {
                pPlotWindow = getPort("in")->getConnectedPorts().at(i)->plot("Value");
            }
            else
            {
                getPort("in")->getConnectedPorts().at(i)->plotToPlotWindow(pPlotWindow, "Value");
            }
        }
        if(!pPlotWindow)
        {
            openPropertiesDialog();
        }
    }
    else
        openPropertiesDialog();
}

//! Returns a string with the component type.
QString GUIComponent::getTypeName()
{
    return mGUIModelObjectAppearance.getTypeName();
}

QString GUIComponent::getTypeCQS()
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getSubComponentTypeCQS(this->getName());
}

void GUIComponent::getParameters(QVector<QString> &qParameterNames, QVector<QString> &qParameterValues, QVector<QString> &qDescriptions, QVector<QString> &qUnits, QVector<QString> &qTypes)
{
    mpParentContainerObject->getCoreSystemAccessPtr()->getParameters(this->getName(), qParameterNames, qParameterValues, qDescriptions, qUnits, qTypes);
}

//! @brief Get a vector with the names of the available parameters
QStringList GUIComponent::getParameterNames()
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterNames(this->getName());
}

QString GUIComponent::getParameterUnit(QString name)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterUnit(this->getName(), name);
}

QString GUIComponent::getParameterDescription(QString name)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterDescription(this->getName(), name);
}

QString GUIComponent::getParameterValue(QString name)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterValue(this->getName(), name);
}

//QString GUIComponent::getParameterValueTxt(QString name)
//{
//    return mpParentContainerObject->getCoreSystemAccessPtr()->getParameterValueTxt(this->getName(), name);
//}

//! @brief Set a parameter value to be mapped to a System parameter
bool GUIComponent::setParameterValue(QString name, QString sysParName, bool force)
{
    return mpParentContainerObject->getCoreSystemAccessPtr()->setParameter(this->getName(), name, sysParName, force);
}

//! @brief Set a start value to be mapped to a System parameter
bool GUIComponent::setStartValue(QString portName, QString variable, QString sysParName)
{
//    QVector<QString> vVariable;
//    QVector<QString> vSysParName;
//    vVariable.append(variable);
//    vSysParName.append(sysParName);
//    return this->getPort(portName)->setStartValueDataByNames(vVariable, vSysParName);
    QString dataName;
    dataName = portName + QString("::Value");
    return mpParentContainerObject->getCoreSystemAccessPtr()->setParameter(this->getName(), dataName, sysParName);
}

//! @brief Set a start value to be mapped to a System parameter
QString GUIComponent::getStartValueTxt(QString portName, QString variable)
{
    QVector<QString> vVariable, vSysParName, vUnit;
    this->getPort(portName)->getStartValueDataNamesValuesAndUnits(vVariable, vSysParName, vUnit);
    int idx = vVariable.indexOf(variable);
    if(idx < 0)
        return "";
    else
        return vSysParName[idx];
}

//! @brief Slot that opens the parameter dialog for the component
void GUIComponent::openPropertiesDialog()
{
    ComponentPropertiesDialog *pDialog = new ComponentPropertiesDialog(this, gpMainWindow);
    pDialog->exec();
    delete pDialog;
}

//! @brief Help function to create ports in the component when it is created
void GUIComponent::createPorts()
{
    //! @todo make sure that all old ports and connections are cleared, (not really necessary in guicomponents)
    QString cqsType = mpParentContainerObject->getCoreSystemAccessPtr()->getSubComponentTypeCQS(getName());
    PortAppearanceMapT::iterator i;
    for (i = mGUIModelObjectAppearance.getPortAppearanceMap().begin(); i != mGUIModelObjectAppearance.getPortAppearanceMap().end(); ++i)
    {
        QString nodeType = mpParentContainerObject->getCoreSystemAccessPtr()->getNodeType(this->getName(), i.key());
        QString portType = mpParentContainerObject->getCoreSystemAccessPtr()->getPortType(this->getName(), i.key());
        i.value().selectPortIcon(cqsType, portType, nodeType);

        qreal x = i.value().x * this->boundingRect().width();
        qreal y = i.value().y * this->boundingRect().height();

        GUIPort *pNewPort = new GUIPort(i.key(), x, y, &(i.value()), this);
        mPortListPtrs.append(pNewPort);
    }
}

int GUIComponent::type() const
{
    return Type;
}

QString GUIComponent::getDefaultParameter(QString name)
{
    if(mDefaultParameters.contains(name))
        return mDefaultParameters.find(name).value();
    else
        return QString();
}

void GUIComponent::setVisible(bool visible)
{
    this->mpIcon->setVisible(visible);
}

//! @brief Save component coredata to XML Dom Element
//! @param[in] rDomElement The dom element to save to
void GUIComponent::saveCoreDataToDomElement(QDomElement &rDomElement)
{
    GUIModelObject::saveCoreDataToDomElement(rDomElement);

    //Save parameters (also core related)
    QDomElement xmlParameters = appendDomElement(rDomElement, HMF_PARAMETERS);
    //! @todo need more efficient fetching of both par names and values in one call to avoid re-searching every time
    QVector<QString> parameterNames, parameterValues, descriptions, units, types;
    getParameters(parameterNames, parameterValues, descriptions, units, types);
    QVector<QString>::iterator pit;
    for(pit = parameterNames.begin(); pit != parameterNames.end(); ++pit)
    {
        QDomElement xmlParam = appendDomElement(xmlParameters, HMF_PARAMETERTAG);
        xmlParam.setAttribute(HMF_NAMETAG, *pit);
        xmlParam.setAttribute(HMF_VALUETAG, mpParentContainerObject->getCoreSystemAccessPtr()->getParameterValue(this->getName(), (*pit)));
        /*if(this->isParameterMappedToSystemParameter(*pit))
        {
            xmlParam.setAttribute(HMF_SYSTEMPARAMETERTAG, this->getSystemParameterKey(*pit));
        }*/
    }

    //Save start values //Is not needed, start values are saved as ordinary parameters! This code snippet can probably be removed.
//    QDomElement xmlStartValues = appendDomElement(rDomElement, HMF_STARTVALUES);
//    QVector<QString> startValueNames;
//    QVector<QString> startValueValuesTxt;
//    QVector<QString> dummy;
//    QList<GUIPort*>::iterator portIt;
//    for(portIt = mPortListPtrs.begin(); portIt != mPortListPtrs.end(); ++portIt)
//    {
//        mpParentContainerObject->getCoreSystemAccessPtr()->getStartValueDataNamesValuesAndUnits(this->getName(), (*portIt)->getPortName(), startValueNames, startValueValuesTxt, dummy);
//        if((!startValueNames.empty()))
//        {
//            for(int i = 0; i < startValueNames.size(); ++i)
//            {
//                QDomElement xmlStartValue = appendDomElement(xmlStartValues, "startvalue");
//                xmlStartValue.setAttribute("portname", (*portIt)->getPortName());
//                xmlStartValue.setAttribute("variable", startValueNames[i]);
//                xmlStartValue.setAttribute("value", startValueValuesTxt[i]);
//            }
//        }
//    }
}
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkNavigationTool.h"
#include "mitkCommon.h"
#include "mitkTestingMacros.h"
#include "mitkDataNode.h"
#include "mitkPointSet.h"
#include "mitkTrackingTool.h"

#include <itkSpatialObject.h>

#include "mitkNDIAuroraTypeInformation.h"

class mitkNavigationToolTestClass
  {
  public:

    static void TestInstantiation()
    {
    // let's create an object of our class
    mitk::NavigationTool::Pointer myNavigationTool = mitk::NavigationTool::New();
    MITK_TEST_CONDITION_REQUIRED(myNavigationTool.IsNotNull(),"Testing instantiation")
    }

    static void TestGetterAndSetter()
    {
    mitk::NavigationTool::Pointer myNavigationTool = mitk::NavigationTool::New();

    //initialize a few things
    mitk::DataNode::Pointer myNode = mitk::DataNode::New();
    myNode->SetName("TestNodeName");
    itk::SpatialObject<3>::Pointer mySpatialObject = itk::SpatialObject<3>::New();

    //set everything
    myNavigationTool->SetType(mitk::NavigationTool::Instrument);
    myNavigationTool->SetIdentifier("Tool#15");
    myNavigationTool->SetDataNode(myNode);
    myNavigationTool->SetSpatialObject(mySpatialObject);
    //notice: cannot test Get/SetTrackingTool because this class cannot be instantiated alone
    myNavigationTool->SetCalibrationFile("Test.srom");
    myNavigationTool->SetSerialNumber("0815");
    myNavigationTool->SetTrackingDeviceType(mitk::NDIAuroraTypeInformation::GetTrackingDeviceName());

    mitk::PointSet::Pointer CalLandmarks = mitk::PointSet::New();
    mitk::Point3D testPt1;
    mitk::FillVector3D(testPt1,1,2,3);
    CalLandmarks->SetPoint(0,testPt1);

    mitk::PointSet::Pointer RegLandmarks = mitk::PointSet::New();
    mitk::Point3D testPt2;
    mitk::FillVector3D(testPt2,4,5,6);
    RegLandmarks->SetPoint(0,testPt2);

    myNavigationTool->SetToolCalibrationLandmarks(CalLandmarks);
    myNavigationTool->SetToolRegistrationLandmarks(RegLandmarks);

    //test getter
    MITK_TEST_CONDITION(myNavigationTool->GetType()==mitk::NavigationTool::Instrument,"Testing getter and setter of type.");
    MITK_TEST_CONDITION(myNavigationTool->GetIdentifier()=="Tool#15","Testing getter and setter of identifier.");
    MITK_TEST_CONDITION(myNavigationTool->GetDataNode()==myNode,"Testing getter and setter of dataNode.");
    MITK_TEST_CONDITION(myNavigationTool->GetSpatialObject()==mySpatialObject,"Testing getter and setter of itk spatial object.");
    MITK_TEST_CONDITION(myNavigationTool->GetCalibrationFile()=="none","Testing getter and setter of calibration file."); //should be none, because file does not exist
    MITK_TEST_CONDITION(myNavigationTool->GetSerialNumber()=="0815","Testing getter and setter of serial number.");
    MITK_TEST_CONDITION(myNavigationTool->GetTrackingDeviceType() == mitk::NDIAuroraTypeInformation::GetTrackingDeviceName(), "Testing getter and setter of tracking device type.");
    MITK_TEST_CONDITION(myNavigationTool->GetToolName()=="TestNodeName","Testing method GetToolName().");
    MITK_TEST_CONDITION(myNavigationTool->GetToolCalibrationLandmarks()->GetPoint(0)[0] == 1.0,"Testing method GetToolCalibrationLandmarks()");
    MITK_TEST_CONDITION(myNavigationTool->GetToolRegistrationLandmarks()->GetPoint(0)[0] == 4.0,"Testing method GetToolRegistrationLandmarks()");
    }

  };
/** This function is testing the TrackingVolume class. */
int mitkNavigationToolTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationTool")

  mitkNavigationToolTestClass::TestInstantiation();
  mitkNavigationToolTestClass::TestGetterAndSetter();

  MITK_TEST_END()
}

<commit_msg>Modified test to test for ToolTip and Axis<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkNavigationTool.h"
#include "mitkCommon.h"
#include "mitkTestingMacros.h"
#include "mitkDataNode.h"
#include "mitkPointSet.h"
#include "mitkTrackingTool.h"

#include <itkSpatialObject.h>

#include "mitkNDIAuroraTypeInformation.h"

class mitkNavigationToolTestClass
  {
  public:

    static bool CompareQuaternions(mitk::Quaternion q1, mitk::Quaternion q2)
    {
      if ((q1.as_vector() - q2.as_vector()).one_norm() < 10e-3)
        return true;
      else
        return false;
    }
    static void TestInstantiation()
    {
    // let's create an object of our class
    mitk::NavigationTool::Pointer myNavigationTool = mitk::NavigationTool::New();
    MITK_TEST_CONDITION_REQUIRED(myNavigationTool.IsNotNull(),"Testing instantiation")
    }

    static void TestGetterAndSetter()
    {
    mitk::NavigationTool::Pointer myNavigationTool = mitk::NavigationTool::New();

    //initialize a few things
    mitk::DataNode::Pointer myNode = mitk::DataNode::New();
    myNode->SetName("TestNodeName");
    itk::SpatialObject<3>::Pointer mySpatialObject = itk::SpatialObject<3>::New();

    //set everything
    myNavigationTool->SetType(mitk::NavigationTool::Instrument);
    myNavigationTool->SetIdentifier("Tool#15");
    myNavigationTool->SetDataNode(myNode);
    myNavigationTool->SetSpatialObject(mySpatialObject);
    //notice: cannot test Get/SetTrackingTool because this class cannot be instantiated alone
    myNavigationTool->SetCalibrationFile("Test.srom");
    myNavigationTool->SetSerialNumber("0815");
    myNavigationTool->SetTrackingDeviceType(mitk::NDIAuroraTypeInformation::GetTrackingDeviceName());

    mitk::PointSet::Pointer CalLandmarks = mitk::PointSet::New();
    mitk::Point3D testPt1;
    mitk::FillVector3D(testPt1,1,2,3);
    CalLandmarks->SetPoint(0,testPt1);

    mitk::PointSet::Pointer RegLandmarks = mitk::PointSet::New();
    mitk::Point3D testPt2;
    mitk::FillVector3D(testPt2,4,5,6);
    RegLandmarks->SetPoint(0,testPt2);

    myNavigationTool->SetToolCalibrationLandmarks(CalLandmarks);
    myNavigationTool->SetToolRegistrationLandmarks(RegLandmarks);

    //test getter
    MITK_TEST_CONDITION(myNavigationTool->GetType()==mitk::NavigationTool::Instrument,"Testing getter and setter of type.");
    MITK_TEST_CONDITION(myNavigationTool->GetIdentifier()=="Tool#15","Testing getter and setter of identifier.");
    MITK_TEST_CONDITION(myNavigationTool->GetDataNode()==myNode,"Testing getter and setter of dataNode.");
    MITK_TEST_CONDITION(myNavigationTool->GetSpatialObject()==mySpatialObject,"Testing getter and setter of itk spatial object.");
    MITK_TEST_CONDITION(myNavigationTool->GetCalibrationFile()=="none","Testing getter and setter of calibration file."); //should be none, because file does not exist
    MITK_TEST_CONDITION(myNavigationTool->GetSerialNumber()=="0815","Testing getter and setter of serial number.");
    MITK_TEST_CONDITION(myNavigationTool->GetTrackingDeviceType() == mitk::NDIAuroraTypeInformation::GetTrackingDeviceName(), "Testing getter and setter of tracking device type.");
    MITK_TEST_CONDITION(myNavigationTool->GetToolName()=="TestNodeName","Testing method GetToolName().");
    MITK_TEST_CONDITION(myNavigationTool->GetToolCalibrationLandmarks()->GetPoint(0)[0] == 1.0,"Testing method GetToolCalibrationLandmarks()");
    MITK_TEST_CONDITION(myNavigationTool->GetToolRegistrationLandmarks()->GetPoint(0)[0] == 4.0,"Testing method GetToolRegistrationLandmarks()");
    }

    static void TestToolTipAndAxis()
    {
      // let's create an object of our class
      mitk::NavigationTool::Pointer myNavigationTool = mitk::NavigationTool::New();
      MITK_TEST_CONDITION_REQUIRED(myNavigationTool.IsNotNull(), "Testing instantiation");
      // define tool tip
      mitk::Point3D toolTip;
      mitk::FillVector3D(toolTip, 1.0, 3.4, 5.6);
      // test Set / GetToolTipPosition
      myNavigationTool->SetToolTipPosition(toolTip);
      MITK_TEST_CONDITION(myNavigationTool->GetToolTipPosition() == toolTip, "Testing Set / GetToolTipPosition");
      // define tool axis
      mitk::Point3D toolAxis;
      mitk::FillVector3D(toolAxis, 1.0, 0.0, 0.0);
      // This tool axis will result in the following transformation
      mitk::Quaternion resultingToolAxisOrientation(0, -sqrt(2)/2.0, 0, sqrt(2)/2.0);
      // test calculation of ToolAxisOrientation
      myNavigationTool->SetToolAxis(toolAxis);
      MITK_TEST_CONDITION(CompareQuaternions(myNavigationTool->GetToolAxisOrientation(),resultingToolAxisOrientation), "Testing caluclation of ToolAxisOrientation");
    }

  };
/** This function is testing the TrackingVolume class. */
int mitkNavigationToolTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationTool")

  mitkNavigationToolTestClass::TestInstantiation();
  mitkNavigationToolTestClass::TestGetterAndSetter();
  mitkNavigationToolTestClass::TestToolTipAndAxis();
  MITK_TEST_END()
}

<|endoftext|>


<commit_before>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015  Vladimir Menshakov

    Android File Transfer For Linux is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Android File Transfer For Linux 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Android File Transfer For Linux.
    If not, see <http://www.gnu.org/licenses/>.
 */

#include <mtp/ptp/Session.h>
#include <mtp/ptp/Messages.h>
#include <mtp/ptp/Container.h>
#include <mtp/ptp/OperationRequest.h>
#include <mtp/ptp/ByteArrayObjectStream.h>
#include <mtp/ptp/JoinedObjectStream.h>
#include <usb/Device.h>
#include <limits>

namespace mtp
{

#define CHECK_RESPONSE(RCODE) do { \
	if ((RCODE) != ResponseType::OK && (RCODE) != ResponseType::SessionAlreadyOpen) \
		throw InvalidResponseException(__func__, (RCODE)); \
} while(false)

	Session::Session(usb::BulkPipePtr pipe, u32 sessionId):
		_packeter(pipe), _sessionId(sessionId), _nextTransactionId(1), _defaultTimeout(10000)
	{
		_deviceInfo = GetDeviceInfoImpl();
		_getPartialObject64Supported = _deviceInfo.Supports(OperationCode::GetPartialObject64);
		_editObjectSupported = _deviceInfo.Supports(OperationCode::BeginEditObject) &&
			_deviceInfo.Supports(OperationCode::EndEditObject) &&
			_deviceInfo.Supports(OperationCode::TruncateObject) &&
			_deviceInfo.Supports(OperationCode::SendPartialObject);
	}

	Session::~Session()
	{ try { Close(); } catch(const std::exception &ex) { } }

	class Session::Transaction
	{
		Session *	_session;
	public:
		u32			Id;

		Transaction(Session *session): _session(session)
		{ session->SetCurrentTransaction(this); }
		~Transaction()
		{ _session->SetCurrentTransaction(0); }
	};

	void Session::SetCurrentTransaction(Transaction *transaction)
	{
		scoped_mutex_lock l(_transactionMutex);
		_transaction = transaction;
		if (_transaction)
			_transaction->Id = _nextTransactionId++;
	}

	void Session::Send(const OperationRequest &req, int timeout)
	{
		if (timeout <= 0)
			timeout = _defaultTimeout;
		Container container(req);
		_packeter.Write(container.Data, timeout);
	}

	void Session::Close()
	{
		scoped_mutex_lock l(_mutex);
		Send(OperationRequest(OperationCode::CloseSession, 0, _sessionId));
		ByteArray data, response;
		ResponseType responseCode;
		_packeter.Read(0, data, responseCode, response, _defaultTimeout);
		//HexDump("payload", data);
	}

	ByteArray Session::Get(u32 transaction, int timeout)
	{
		if (timeout <= 0)
			timeout = _defaultTimeout;
		ByteArray data, response;
		ResponseType responseCode;
		_packeter.Read(transaction, data, responseCode, response, timeout);
		CHECK_RESPONSE(responseCode);
		return data;
	}

	msg::DeviceInfo Session::GetDeviceInfoImpl()
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetDeviceInfo, transaction.Id));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data); //operation code + session id
		msg::DeviceInfo gdi;
		gdi.Read(stream);
		return gdi;
	}

	msg::ObjectHandles Session::GetObjectHandles(u32 storageId, u32 objectFormat, u32 parent, int timeout)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectHandles, transaction.Id, storageId, objectFormat, parent), timeout);
		ByteArray data = Get(transaction.Id, timeout);
		InputStream stream(data);

		msg::ObjectHandles goh;
		goh.Read(stream);
		return goh;
	}

	msg::StorageIDs Session::GetStorageIDs()
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetStorageIDs, transaction.Id));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);

		msg::StorageIDs gsi;
		gsi.Read(stream);
		return gsi;
	}

	msg::StorageInfo Session::GetStorageInfo(u32 storageId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetStorageInfo, transaction.Id, storageId));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);
		msg::StorageInfo gsi;
		gsi.Read(stream);
		return gsi;
	}

	Session::NewObjectInfo Session::CreateDirectory(const std::string &name, mtp::u32 parentId, mtp::u32 storageId, AssociationType type)
	{
		mtp::msg::ObjectInfo oi;
		oi.Filename = name;
		oi.ParentObject = parentId;
		oi.StorageId = storageId;
		oi.ObjectFormat = mtp::ObjectFormat::Association;
		oi.AssociationType = type;
		mtp::Session::NewObjectInfo noi = SendObjectInfo(oi, storageId, parentId);

		//SendObject(std::make_shared<ByteArrayObjectInputStream>(ByteArray()));
		return noi;
	}

	msg::ObjectInfo Session::GetObjectInfo(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectInfo, transaction.Id, objectId));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);
		msg::ObjectInfo goi;
		goi.Read(stream);
		return goi;
	}

	msg::ObjectPropsSupported Session::GetObjectPropsSupported(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectPropsSupported, transaction.Id, objectId));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);
		msg::ObjectPropsSupported ops;
		ops.Read(stream);
		return ops;
	}

	void Session::GetObject(u32 objectId, const IObjectOutputStreamPtr &outputStream)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObject, transaction.Id, objectId));
		ByteArray response;
		ResponseType responseCode;
		_packeter.Read(transaction.Id, outputStream, responseCode, response, _defaultTimeout);
		CHECK_RESPONSE(responseCode);
	}

	ByteArray Session::GetPartialObject(u32 objectId, u64 offset, u32 size)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		if (_getPartialObject64Supported)
			Send(OperationRequest(OperationCode::GetPartialObject64, transaction.Id, objectId, offset, offset >> 32, size));
		else
		{
			if (offset + size > std::numeric_limits<u32>::max())
				throw std::runtime_error("32 bit overflow for GetPartialObject");
			Send(OperationRequest(OperationCode::GetPartialObject, transaction.Id, objectId, offset, size));
		}
		return Get(transaction.Id);
	}

	Session::NewObjectInfo Session::SendObjectInfo(const msg::ObjectInfo &objectInfo, u32 storageId, u32 parentObject)
	{
		if (objectInfo.Filename.empty())
			throw std::runtime_error("object filename must not be empty");
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SendObjectInfo, transaction.Id, storageId, parentObject));
		{
			DataRequest req(OperationCode::SendObjectInfo, transaction.Id);
			OutputStream stream(req.Data);
			objectInfo.Write(stream);
			Container container(req);
			_packeter.Write(container.Data, _defaultTimeout);
		}
		ByteArray data, response;
		ResponseType responseCode;
		_packeter.Read(transaction.Id, data, responseCode, response, _defaultTimeout);
		//HexDump("response", response);
		CHECK_RESPONSE(responseCode);
		InputStream stream(response);
		NewObjectInfo noi;
		stream >> noi.StorageId;
		stream >> noi.ParentObjectId;
		stream >> noi.ObjectId;
		return noi;
	}

	void Session::SendObject(const IObjectInputStreamPtr &inputStream, int timeout)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SendObject, transaction.Id));
		{
			DataRequest req(OperationCode::SendObject, transaction.Id);
			Container container(req, inputStream);
			_packeter.Write(std::make_shared<JoinedObjectInputStream>(std::make_shared<ByteArrayObjectInputStream>(container.Data), inputStream), timeout);
		}
		Get(transaction.Id);
	}

	void Session::BeginEditObject(u32 objectId)
	{
		try
		{ EndEditObject(objectId); }
		catch(const std::exception &ex)
		{ }
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::BeginEditObject, transaction.Id, objectId));
		Get(transaction.Id);
	}

	void Session::SendPartialObject(u32 objectId, u64 offset, const ByteArray &data)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SendPartialObject, transaction.Id, objectId, offset, offset >> 32, data.size()));
		{
			DataRequest req(OperationCode::SendPartialObject, transaction.Id);
			IObjectInputStreamPtr inputStream = std::make_shared<ByteArrayObjectInputStream>(data);
			Container container(req, inputStream);
			_packeter.Write(std::make_shared<JoinedObjectInputStream>(std::make_shared<ByteArrayObjectInputStream>(container.Data), inputStream), _defaultTimeout);
		}
		Get(transaction.Id);
	}

	void Session::TruncateObject(u32 objectId, u64 size)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		//64 bit size?
		Send(OperationRequest(OperationCode::TruncateObject, transaction.Id, objectId, size, size >> 32));
		Get(transaction.Id);
	}

	void Session::EndEditObject(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::EndEditObject, transaction.Id, objectId));
		Get(transaction.Id);
	}

	void Session::SetObjectProperty(u32 objectId, ObjectProperty property, const ByteArray &value)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SetObjectPropValue, transaction.Id, objectId, (u16)property));
		{
			DataRequest req(OperationCode::SetObjectPropValue, transaction.Id);
			req.Append(value);
			Container container(req);
			_packeter.Write(container.Data, _defaultTimeout);
		}
		Get(transaction.Id);
	}

	void Session::SetObjectProperty(u32 objectId, ObjectProperty property, const std::string &value)
	{
		ByteArray data;
		data.reserve(value.size() * 2 + 1);
		OutputStream stream(data);
		stream << value;
		SetObjectProperty(objectId, property, data);
	}

	ByteArray Session::GetObjectProperty(u32 objectId, ObjectProperty property)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectPropValue, transaction.Id, objectId, (u16)property));
		return Get(transaction.Id);
	}

	u64 Session::GetObjectIntegerProperty(u32 objectId, ObjectProperty property)
	{
		ByteArray data = GetObjectProperty(objectId, property);
		InputStream s(data);
		switch(data.size())
		{
		case 8: return s.Read64();
		case 4: return s.Read32();
		case 2: return s.Read16();
		case 1: return s.Read8();
		default:
			throw std::runtime_error("unexpected length for numeric property");
		}
	}

	std::string Session::GetObjectStringProperty(u32 objectId, ObjectProperty property)
	{
		ByteArray data = GetObjectProperty(objectId, property);
		InputStream s(data);
		std::string value;
		s >> value;
		return value;
	}

	void Session::DeleteObject(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::DeleteObject, transaction.Id, objectId, 0));
		Get(transaction.Id);
	}

	ByteArray Session::GetDeviceProperty(DeviceProperty property)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetDevicePropValue, transaction.Id, (u16)property));
		return Get(transaction.Id);
	}

	Session::ObjectEditSession::ObjectEditSession(const SessionPtr & session, u32 objectId): _session(session), _objectId(objectId)
	{
		session->BeginEditObject(objectId);
	}

	Session::ObjectEditSession::~ObjectEditSession()
	{
		_session->EndEditObject(_objectId);
	}

	void Session::ObjectEditSession::Truncate(u64 size)
	{
		_session->TruncateObject(_objectId, size);
	}

	void Session::ObjectEditSession::Send(u64 offset, const ByteArray &data)
	{
		_session->SendPartialObject(_objectId, offset, data);
	}

	void Session::AbortCurrentTransaction(int timeout)
	{
		u32 transactionId;
		{
			scoped_mutex_lock l(_transactionMutex);
			if (!_transaction)
				throw std::runtime_error("no transaction in progress");
			transactionId = _transaction->Id;
		}
		ByteArray data;
		OutputStream s(data);
		s.Write16(0x4001);
		s.Write32(transactionId);
		HexDump("abort control message", data);
		_packeter.GetPipe()->GetDevice()->WriteControl(0x21, 0x64, 0, 0, data, timeout);
		/* 0x21: host-to-device, class specific, recipient - interface, 0x64: cancel request */
	}

}
<commit_msg>replaced 0x21 with enum<commit_after>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015  Vladimir Menshakov

    Android File Transfer For Linux is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Android File Transfer For Linux 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Android File Transfer For Linux.
    If not, see <http://www.gnu.org/licenses/>.
 */

#include <mtp/ptp/Session.h>
#include <mtp/ptp/Messages.h>
#include <mtp/ptp/Container.h>
#include <mtp/ptp/OperationRequest.h>
#include <mtp/ptp/ByteArrayObjectStream.h>
#include <mtp/ptp/JoinedObjectStream.h>
#include <mtp/usb/Request.h>
#include <usb/Device.h>
#include <limits>

namespace mtp
{

#define CHECK_RESPONSE(RCODE) do { \
	if ((RCODE) != ResponseType::OK && (RCODE) != ResponseType::SessionAlreadyOpen) \
		throw InvalidResponseException(__func__, (RCODE)); \
} while(false)

	Session::Session(usb::BulkPipePtr pipe, u32 sessionId):
		_packeter(pipe), _sessionId(sessionId), _nextTransactionId(1), _defaultTimeout(10000)
	{
		_deviceInfo = GetDeviceInfoImpl();
		_getPartialObject64Supported = _deviceInfo.Supports(OperationCode::GetPartialObject64);
		_editObjectSupported = _deviceInfo.Supports(OperationCode::BeginEditObject) &&
			_deviceInfo.Supports(OperationCode::EndEditObject) &&
			_deviceInfo.Supports(OperationCode::TruncateObject) &&
			_deviceInfo.Supports(OperationCode::SendPartialObject);
	}

	Session::~Session()
	{ try { Close(); } catch(const std::exception &ex) { } }

	class Session::Transaction
	{
		Session *	_session;
	public:
		u32			Id;

		Transaction(Session *session): _session(session)
		{ session->SetCurrentTransaction(this); }
		~Transaction()
		{ _session->SetCurrentTransaction(0); }
	};

	void Session::SetCurrentTransaction(Transaction *transaction)
	{
		scoped_mutex_lock l(_transactionMutex);
		_transaction = transaction;
		if (_transaction)
			_transaction->Id = _nextTransactionId++;
	}

	void Session::Send(const OperationRequest &req, int timeout)
	{
		if (timeout <= 0)
			timeout = _defaultTimeout;
		Container container(req);
		_packeter.Write(container.Data, timeout);
	}

	void Session::Close()
	{
		scoped_mutex_lock l(_mutex);
		Send(OperationRequest(OperationCode::CloseSession, 0, _sessionId));
		ByteArray data, response;
		ResponseType responseCode;
		_packeter.Read(0, data, responseCode, response, _defaultTimeout);
		//HexDump("payload", data);
	}

	ByteArray Session::Get(u32 transaction, int timeout)
	{
		if (timeout <= 0)
			timeout = _defaultTimeout;
		ByteArray data, response;
		ResponseType responseCode;
		_packeter.Read(transaction, data, responseCode, response, timeout);
		CHECK_RESPONSE(responseCode);
		return data;
	}

	msg::DeviceInfo Session::GetDeviceInfoImpl()
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetDeviceInfo, transaction.Id));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data); //operation code + session id
		msg::DeviceInfo gdi;
		gdi.Read(stream);
		return gdi;
	}

	msg::ObjectHandles Session::GetObjectHandles(u32 storageId, u32 objectFormat, u32 parent, int timeout)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectHandles, transaction.Id, storageId, objectFormat, parent), timeout);
		ByteArray data = Get(transaction.Id, timeout);
		InputStream stream(data);

		msg::ObjectHandles goh;
		goh.Read(stream);
		return goh;
	}

	msg::StorageIDs Session::GetStorageIDs()
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetStorageIDs, transaction.Id));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);

		msg::StorageIDs gsi;
		gsi.Read(stream);
		return gsi;
	}

	msg::StorageInfo Session::GetStorageInfo(u32 storageId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetStorageInfo, transaction.Id, storageId));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);
		msg::StorageInfo gsi;
		gsi.Read(stream);
		return gsi;
	}

	Session::NewObjectInfo Session::CreateDirectory(const std::string &name, mtp::u32 parentId, mtp::u32 storageId, AssociationType type)
	{
		mtp::msg::ObjectInfo oi;
		oi.Filename = name;
		oi.ParentObject = parentId;
		oi.StorageId = storageId;
		oi.ObjectFormat = mtp::ObjectFormat::Association;
		oi.AssociationType = type;
		mtp::Session::NewObjectInfo noi = SendObjectInfo(oi, storageId, parentId);

		//SendObject(std::make_shared<ByteArrayObjectInputStream>(ByteArray()));
		return noi;
	}

	msg::ObjectInfo Session::GetObjectInfo(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectInfo, transaction.Id, objectId));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);
		msg::ObjectInfo goi;
		goi.Read(stream);
		return goi;
	}

	msg::ObjectPropsSupported Session::GetObjectPropsSupported(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectPropsSupported, transaction.Id, objectId));
		ByteArray data = Get(transaction.Id);
		InputStream stream(data);
		msg::ObjectPropsSupported ops;
		ops.Read(stream);
		return ops;
	}

	void Session::GetObject(u32 objectId, const IObjectOutputStreamPtr &outputStream)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObject, transaction.Id, objectId));
		ByteArray response;
		ResponseType responseCode;
		_packeter.Read(transaction.Id, outputStream, responseCode, response, _defaultTimeout);
		CHECK_RESPONSE(responseCode);
	}

	ByteArray Session::GetPartialObject(u32 objectId, u64 offset, u32 size)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		if (_getPartialObject64Supported)
			Send(OperationRequest(OperationCode::GetPartialObject64, transaction.Id, objectId, offset, offset >> 32, size));
		else
		{
			if (offset + size > std::numeric_limits<u32>::max())
				throw std::runtime_error("32 bit overflow for GetPartialObject");
			Send(OperationRequest(OperationCode::GetPartialObject, transaction.Id, objectId, offset, size));
		}
		return Get(transaction.Id);
	}

	Session::NewObjectInfo Session::SendObjectInfo(const msg::ObjectInfo &objectInfo, u32 storageId, u32 parentObject)
	{
		if (objectInfo.Filename.empty())
			throw std::runtime_error("object filename must not be empty");
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SendObjectInfo, transaction.Id, storageId, parentObject));
		{
			DataRequest req(OperationCode::SendObjectInfo, transaction.Id);
			OutputStream stream(req.Data);
			objectInfo.Write(stream);
			Container container(req);
			_packeter.Write(container.Data, _defaultTimeout);
		}
		ByteArray data, response;
		ResponseType responseCode;
		_packeter.Read(transaction.Id, data, responseCode, response, _defaultTimeout);
		//HexDump("response", response);
		CHECK_RESPONSE(responseCode);
		InputStream stream(response);
		NewObjectInfo noi;
		stream >> noi.StorageId;
		stream >> noi.ParentObjectId;
		stream >> noi.ObjectId;
		return noi;
	}

	void Session::SendObject(const IObjectInputStreamPtr &inputStream, int timeout)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SendObject, transaction.Id));
		{
			DataRequest req(OperationCode::SendObject, transaction.Id);
			Container container(req, inputStream);
			_packeter.Write(std::make_shared<JoinedObjectInputStream>(std::make_shared<ByteArrayObjectInputStream>(container.Data), inputStream), timeout);
		}
		Get(transaction.Id);
	}

	void Session::BeginEditObject(u32 objectId)
	{
		try
		{ EndEditObject(objectId); }
		catch(const std::exception &ex)
		{ }
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::BeginEditObject, transaction.Id, objectId));
		Get(transaction.Id);
	}

	void Session::SendPartialObject(u32 objectId, u64 offset, const ByteArray &data)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SendPartialObject, transaction.Id, objectId, offset, offset >> 32, data.size()));
		{
			DataRequest req(OperationCode::SendPartialObject, transaction.Id);
			IObjectInputStreamPtr inputStream = std::make_shared<ByteArrayObjectInputStream>(data);
			Container container(req, inputStream);
			_packeter.Write(std::make_shared<JoinedObjectInputStream>(std::make_shared<ByteArrayObjectInputStream>(container.Data), inputStream), _defaultTimeout);
		}
		Get(transaction.Id);
	}

	void Session::TruncateObject(u32 objectId, u64 size)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		//64 bit size?
		Send(OperationRequest(OperationCode::TruncateObject, transaction.Id, objectId, size, size >> 32));
		Get(transaction.Id);
	}

	void Session::EndEditObject(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::EndEditObject, transaction.Id, objectId));
		Get(transaction.Id);
	}

	void Session::SetObjectProperty(u32 objectId, ObjectProperty property, const ByteArray &value)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::SetObjectPropValue, transaction.Id, objectId, (u16)property));
		{
			DataRequest req(OperationCode::SetObjectPropValue, transaction.Id);
			req.Append(value);
			Container container(req);
			_packeter.Write(container.Data, _defaultTimeout);
		}
		Get(transaction.Id);
	}

	void Session::SetObjectProperty(u32 objectId, ObjectProperty property, const std::string &value)
	{
		ByteArray data;
		data.reserve(value.size() * 2 + 1);
		OutputStream stream(data);
		stream << value;
		SetObjectProperty(objectId, property, data);
	}

	ByteArray Session::GetObjectProperty(u32 objectId, ObjectProperty property)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetObjectPropValue, transaction.Id, objectId, (u16)property));
		return Get(transaction.Id);
	}

	u64 Session::GetObjectIntegerProperty(u32 objectId, ObjectProperty property)
	{
		ByteArray data = GetObjectProperty(objectId, property);
		InputStream s(data);
		switch(data.size())
		{
		case 8: return s.Read64();
		case 4: return s.Read32();
		case 2: return s.Read16();
		case 1: return s.Read8();
		default:
			throw std::runtime_error("unexpected length for numeric property");
		}
	}

	std::string Session::GetObjectStringProperty(u32 objectId, ObjectProperty property)
	{
		ByteArray data = GetObjectProperty(objectId, property);
		InputStream s(data);
		std::string value;
		s >> value;
		return value;
	}

	void Session::DeleteObject(u32 objectId)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::DeleteObject, transaction.Id, objectId, 0));
		Get(transaction.Id);
	}

	ByteArray Session::GetDeviceProperty(DeviceProperty property)
	{
		scoped_mutex_lock l(_mutex);
		Transaction transaction(this);
		Send(OperationRequest(OperationCode::GetDevicePropValue, transaction.Id, (u16)property));
		return Get(transaction.Id);
	}

	Session::ObjectEditSession::ObjectEditSession(const SessionPtr & session, u32 objectId): _session(session), _objectId(objectId)
	{
		session->BeginEditObject(objectId);
	}

	Session::ObjectEditSession::~ObjectEditSession()
	{
		_session->EndEditObject(_objectId);
	}

	void Session::ObjectEditSession::Truncate(u64 size)
	{
		_session->TruncateObject(_objectId, size);
	}

	void Session::ObjectEditSession::Send(u64 offset, const ByteArray &data)
	{
		_session->SendPartialObject(_objectId, offset, data);
	}

	void Session::AbortCurrentTransaction(int timeout)
	{
		u32 transactionId;
		{
			scoped_mutex_lock l(_transactionMutex);
			if (!_transaction)
				throw std::runtime_error("no transaction in progress");
			transactionId = _transaction->Id;
		}
		ByteArray data;
		OutputStream s(data);
		s.Write16(0x4001);
		s.Write32(transactionId);
		HexDump("abort control message", data);
		/* 0x21: host-to-device, class specific, recipient - interface, 0x64: cancel request */
		_packeter.GetPipe()->GetDevice()->WriteControl(
			(u8)(usb::RequestType::HostToDevice | usb::RequestType::Class | usb::RequestType::Interface),
			0x64,
			0, 0, data, timeout);
	}

}
<|endoftext|>


<commit_before>#include "vulkan.hpp"
#include "vulkan_symbol_wrapper.h"
#include <stdexcept>
#include <vector>
#include "vulkan_events.hpp"

#ifdef HAVE_GLFW
#include <GLFW/glfw3.h>
#endif

#ifdef HAVE_DYLIB
#include <dlfcn.h>
#endif

using namespace std;

#undef VULKAN_DEBUG

namespace Vulkan
{
Context::Context(const char **instance_ext, uint32_t instance_ext_count, const char **device_ext,
                 uint32_t device_ext_count)
    : owned_instance(true)
    , owned_device(true)
{
	if (!create_instance(instance_ext, instance_ext_count))
	{
		destroy();
		throw runtime_error("Failed to create Vulkan instance.");
	}

	VkPhysicalDeviceFeatures features = {};
	if (!create_device(VK_NULL_HANDLE, VK_NULL_HANDLE, device_ext, device_ext_count, nullptr, 0, &features))
	{
		destroy();
		throw runtime_error("Failed to create Vulkan device.");
	}
}

bool Context::init_loader(PFN_vkGetInstanceProcAddr addr)
{
	if (!addr)
	{
#ifdef HAVE_DYLIB
		static void *module;
		if (!module)
		{
			module = dlopen("libvulkan.so", RTLD_LOCAL | RTLD_LAZY);
			if (!module)
				return false;
		}

		addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(module, "vkGetInstanceProcAddr"));
		if (!addr)
			return false;
#else
		return false;
#endif
	}

	vulkan_symbol_wrapper_init(addr);
	return vulkan_symbol_wrapper_load_global_symbols();
}

Context::Context(VkInstance instance, VkPhysicalDevice gpu, VkDevice device, VkQueue queue, uint32_t queue_family)
    : device(device)
    , instance(instance)
    , gpu(gpu)
    , queue(queue)
    , queue_family(queue_family)
    , owned_instance(false)
    , owned_device(false)
{
	vulkan_symbol_wrapper_load_core_instance_symbols(instance);
	vulkan_symbol_wrapper_load_core_device_symbols(device);

	vkGetPhysicalDeviceProperties(gpu, &gpu_props);
	vkGetPhysicalDeviceMemoryProperties(gpu, &mem_props);
}

Context::Context(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface,
                 const char **required_device_extensions, unsigned num_required_device_extensions,
                 const char **required_device_layers, unsigned num_required_device_layers,
                 const VkPhysicalDeviceFeatures *required_features)
    : instance(instance)
    , owned_instance(false)
    , owned_device(true)
{
	vulkan_symbol_wrapper_load_core_instance_symbols(instance);
	if (!create_device(gpu, surface, required_device_extensions, num_required_device_extensions, required_device_layers,
	                   num_required_device_layers, required_features))
	{
		destroy();
		throw runtime_error("Failed to create Vulkan device.");
	}
}

void Context::destroy()
{
	if (device != VK_NULL_HANDLE)
		vkDeviceWaitIdle(device);

#ifdef VULKAN_DEBUG
	if (debug_callback)
		vkDestroyDebugReportCallbackEXT(instance, debug_callback, nullptr);
#endif

	if (owned_device && device != VK_NULL_HANDLE)
		vkDestroyDevice(device, nullptr);
	if (owned_instance && instance != VK_NULL_HANDLE)
		vkDestroyInstance(instance, nullptr);
}

Context::~Context()
{
	destroy();
}

const VkApplicationInfo &Context::get_application_info()
{
	static const VkApplicationInfo info = {
		VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "paraLLEl PSX", 0, "paraLLEl PSX", 0, VK_MAKE_VERSION(1, 0, 18),
	};
	return info;
}

#ifdef VULKAN_DEBUG
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(VkDebugReportFlagsEXT flags,
                                                      VkDebugReportObjectTypeEXT objectType, uint64_t object,
                                                      size_t location, int32_t messageCode, const char *pLayerPrefix,
                                                      const char *pMessage, void *pUserData)
{
	(void)objectType;
	(void)object;
	(void)location;
	(void)messageCode;
	(void)pUserData;

	if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
	{
		fprintf(stderr, "[Vulkan]: Error: %s: %s\n", pLayerPrefix, pMessage);
	}
	else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
	{
		fprintf(stderr, "[Vulkan]: Warning: %s: %s\n", pLayerPrefix, pMessage);
	}
	else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
	{
		//fprintf(stderr, "[Vulkan]: Performance warning: %s: %s\n", pLayerPrefix, pMessage);
	}
	else
	{
		fprintf(stderr, "[Vulkan]: Information: %s: %s\n", pLayerPrefix, pMessage);
	}

	return VK_FALSE;
}
#endif

bool Context::create_instance(const char **instance_ext, uint32_t instance_ext_count)
{
	VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
	info.pApplicationInfo = &get_application_info();

	vector<const char *> instance_exts;
	vector<const char *> instance_layers;
	for (uint32_t i = 0; i < instance_ext_count; i++)
		instance_exts.push_back(instance_ext[i]);

#ifdef VULKAN_DEBUG
	instance_exts.push_back("VK_EXT_debug_report");
	instance_layers.push_back("VK_LAYER_LUNARG_standard_validation");
#endif

	info.enabledExtensionCount = instance_exts.size();
	info.ppEnabledExtensionNames = instance_exts.empty() ? nullptr : instance_exts.data();
	info.enabledLayerCount = instance_layers.size();
	info.ppEnabledLayerNames = instance_layers.empty() ? nullptr : instance_layers.data();

	if (vkCreateInstance(&info, nullptr, &instance) != VK_SUCCESS)
		return false;

	vulkan_symbol_wrapper_load_core_instance_symbols(instance);

#ifdef VULKAN_DEBUG
	VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkCreateDebugReportCallbackEXT);
	VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkDebugReportMessageEXT);
	VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkDestroyDebugReportCallbackEXT);

	{
		VkDebugReportCallbackCreateInfoEXT info = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT };
		info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
		             VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
		info.pfnCallback = vulkan_debug_cb;
		vkCreateDebugReportCallbackEXT(instance, &info, NULL, &debug_callback);
	}
#endif
	return true;
}

bool Context::create_device(VkPhysicalDevice gpu, VkSurfaceKHR surface, const char **required_device_extensions,
                            unsigned num_required_device_extensions, const char **required_device_layers,
                            unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features)
{
	if (gpu == VK_NULL_HANDLE)
	{
		uint32_t gpu_count = 0;
		V(vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr));
		vector<VkPhysicalDevice> gpus(gpu_count);
		V(vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data()));
		gpu = gpus.front();
	}

	this->gpu = gpu;
	vkGetPhysicalDeviceProperties(gpu, &gpu_props);
	vkGetPhysicalDeviceMemoryProperties(gpu, &mem_props);

	uint32_t queue_count;
	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, nullptr);
	vector<VkQueueFamilyProperties> queue_props(queue_count);
	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, queue_props.data());

	if (surface != VK_NULL_HANDLE)
	{
		VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceSurfaceSupportKHR);
	}

	bool found_queue = false;
	for (unsigned i = 0; i < queue_count; i++)
	{
		VkBool32 supported = surface == VK_NULL_HANDLE;
#ifdef HAVE_GLFW
		supported = glfwGetPhysicalDevicePresentationSupport(instance, gpu, i);
#else
		if (surface != VK_NULL_HANDLE)
			vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supported);
#endif

		VkQueueFlags required = VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT;
		if (supported && ((queue_props[i].queueFlags & required) == required))
		{
			found_queue = true;
			queue_family = i;
			break;
		}
	}

	if (!found_queue)
		return false;

	static const float prio = 1.0f;
	VkDeviceQueueCreateInfo queue_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };

	VkDeviceCreateInfo device_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
	device_info.pQueueCreateInfos = &queue_info;

	queue_info.queueFamilyIndex = queue_family;
	queue_info.queueCount = 1;
	queue_info.pQueuePriorities = &prio;
	device_info.queueCreateInfoCount = 1;

	// Should query for these, but no big deal for now.
	device_info.ppEnabledExtensionNames = required_device_extensions;
	device_info.enabledExtensionCount = num_required_device_extensions;
	device_info.ppEnabledLayerNames = required_device_layers;
	device_info.enabledLayerCount = num_required_device_layers;

	VkPhysicalDeviceFeatures enabled_features = *required_features;
	{
		VkPhysicalDeviceFeatures features;
		vkGetPhysicalDeviceFeatures(gpu, &features);
		if (features.textureCompressionETC2)
			enabled_features.textureCompressionETC2 = VK_TRUE;
		if (features.textureCompressionBC)
			enabled_features.textureCompressionBC = VK_TRUE;
		if (features.textureCompressionASTC_LDR)
			enabled_features.textureCompressionASTC_LDR = VK_TRUE;
		if (features.fullDrawIndexUint32)
			enabled_features.fullDrawIndexUint32 = VK_TRUE;
		if (features.imageCubeArray)
			enabled_features.imageCubeArray = VK_TRUE;
	}

	device_info.pEnabledFeatures = &enabled_features;

#ifdef VULKAN_DEBUG
	static const char *device_layers[] = { "VK_LAYER_LUNARG_standard_validation" };
	device_info.enabledLayerCount = 1;
	device_info.ppEnabledLayerNames = device_layers;
#endif

	if (vkCreateDevice(gpu, &device_info, nullptr, &device) != VK_SUCCESS)
		return false;

	vulkan_symbol_wrapper_load_core_device_symbols(device);
	vkGetDeviceQueue(device, queue_family, 0, &queue);
	return true;
}
}
<commit_msg>Log the GPU name.<commit_after>#include "vulkan.hpp"
#include "vulkan_symbol_wrapper.h"
#include <stdexcept>
#include <vector>
#include "vulkan_events.hpp"

#ifdef HAVE_GLFW
#include <GLFW/glfw3.h>
#endif

#ifdef HAVE_DYLIB
#include <dlfcn.h>
#endif

using namespace std;

#undef VULKAN_DEBUG

namespace Vulkan
{
Context::Context(const char **instance_ext, uint32_t instance_ext_count, const char **device_ext,
                 uint32_t device_ext_count)
    : owned_instance(true)
    , owned_device(true)
{
	if (!create_instance(instance_ext, instance_ext_count))
	{
		destroy();
		throw runtime_error("Failed to create Vulkan instance.");
	}

	VkPhysicalDeviceFeatures features = {};
	if (!create_device(VK_NULL_HANDLE, VK_NULL_HANDLE, device_ext, device_ext_count, nullptr, 0, &features))
	{
		destroy();
		throw runtime_error("Failed to create Vulkan device.");
	}
}

bool Context::init_loader(PFN_vkGetInstanceProcAddr addr)
{
	if (!addr)
	{
#ifdef HAVE_DYLIB
		static void *module;
		if (!module)
		{
			module = dlopen("libvulkan.so", RTLD_LOCAL | RTLD_LAZY);
			if (!module)
				return false;
		}

		addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(module, "vkGetInstanceProcAddr"));
		if (!addr)
			return false;
#else
		return false;
#endif
	}

	vulkan_symbol_wrapper_init(addr);
	return vulkan_symbol_wrapper_load_global_symbols();
}

Context::Context(VkInstance instance, VkPhysicalDevice gpu, VkDevice device, VkQueue queue, uint32_t queue_family)
    : device(device)
    , instance(instance)
    , gpu(gpu)
    , queue(queue)
    , queue_family(queue_family)
    , owned_instance(false)
    , owned_device(false)
{
	vulkan_symbol_wrapper_load_core_instance_symbols(instance);
	vulkan_symbol_wrapper_load_core_device_symbols(device);

	vkGetPhysicalDeviceProperties(gpu, &gpu_props);
	vkGetPhysicalDeviceMemoryProperties(gpu, &mem_props);
}

Context::Context(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface,
                 const char **required_device_extensions, unsigned num_required_device_extensions,
                 const char **required_device_layers, unsigned num_required_device_layers,
                 const VkPhysicalDeviceFeatures *required_features)
    : instance(instance)
    , owned_instance(false)
    , owned_device(true)
{
	vulkan_symbol_wrapper_load_core_instance_symbols(instance);
	if (!create_device(gpu, surface, required_device_extensions, num_required_device_extensions, required_device_layers,
	                   num_required_device_layers, required_features))
	{
		destroy();
		throw runtime_error("Failed to create Vulkan device.");
	}
}

void Context::destroy()
{
	if (device != VK_NULL_HANDLE)
		vkDeviceWaitIdle(device);

#ifdef VULKAN_DEBUG
	if (debug_callback)
		vkDestroyDebugReportCallbackEXT(instance, debug_callback, nullptr);
#endif

	if (owned_device && device != VK_NULL_HANDLE)
		vkDestroyDevice(device, nullptr);
	if (owned_instance && instance != VK_NULL_HANDLE)
		vkDestroyInstance(instance, nullptr);
}

Context::~Context()
{
	destroy();
}

const VkApplicationInfo &Context::get_application_info()
{
	static const VkApplicationInfo info = {
		VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "paraLLEl PSX", 0, "paraLLEl PSX", 0, VK_MAKE_VERSION(1, 0, 18),
	};
	return info;
}

#ifdef VULKAN_DEBUG
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(VkDebugReportFlagsEXT flags,
                                                      VkDebugReportObjectTypeEXT objectType, uint64_t object,
                                                      size_t location, int32_t messageCode, const char *pLayerPrefix,
                                                      const char *pMessage, void *pUserData)
{
	(void)objectType;
	(void)object;
	(void)location;
	(void)messageCode;
	(void)pUserData;

	if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
	{
		fprintf(stderr, "[Vulkan]: Error: %s: %s\n", pLayerPrefix, pMessage);
	}
	else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
	{
		fprintf(stderr, "[Vulkan]: Warning: %s: %s\n", pLayerPrefix, pMessage);
	}
	else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
	{
		//fprintf(stderr, "[Vulkan]: Performance warning: %s: %s\n", pLayerPrefix, pMessage);
	}
	else
	{
		fprintf(stderr, "[Vulkan]: Information: %s: %s\n", pLayerPrefix, pMessage);
	}

	return VK_FALSE;
}
#endif

bool Context::create_instance(const char **instance_ext, uint32_t instance_ext_count)
{
	VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
	info.pApplicationInfo = &get_application_info();

	vector<const char *> instance_exts;
	vector<const char *> instance_layers;
	for (uint32_t i = 0; i < instance_ext_count; i++)
		instance_exts.push_back(instance_ext[i]);

#ifdef VULKAN_DEBUG
	instance_exts.push_back("VK_EXT_debug_report");
	instance_layers.push_back("VK_LAYER_LUNARG_standard_validation");
#endif

	info.enabledExtensionCount = instance_exts.size();
	info.ppEnabledExtensionNames = instance_exts.empty() ? nullptr : instance_exts.data();
	info.enabledLayerCount = instance_layers.size();
	info.ppEnabledLayerNames = instance_layers.empty() ? nullptr : instance_layers.data();

	if (vkCreateInstance(&info, nullptr, &instance) != VK_SUCCESS)
		return false;

	vulkan_symbol_wrapper_load_core_instance_symbols(instance);

#ifdef VULKAN_DEBUG
	VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkCreateDebugReportCallbackEXT);
	VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkDebugReportMessageEXT);
	VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkDestroyDebugReportCallbackEXT);

	{
		VkDebugReportCallbackCreateInfoEXT info = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT };
		info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
		             VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
		info.pfnCallback = vulkan_debug_cb;
		vkCreateDebugReportCallbackEXT(instance, &info, NULL, &debug_callback);
	}
#endif
	return true;
}

bool Context::create_device(VkPhysicalDevice gpu, VkSurfaceKHR surface, const char **required_device_extensions,
                            unsigned num_required_device_extensions, const char **required_device_layers,
                            unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features)
{
	if (gpu == VK_NULL_HANDLE)
	{
		uint32_t gpu_count = 0;
		V(vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr));
		vector<VkPhysicalDevice> gpus(gpu_count);
		V(vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data()));
		gpu = gpus.front();
	}

	this->gpu = gpu;
	vkGetPhysicalDeviceProperties(gpu, &gpu_props);
	vkGetPhysicalDeviceMemoryProperties(gpu, &mem_props);

	LOGI("Vulkan GPU: %s\n", gpu_props.deviceName);

	uint32_t queue_count;
	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, nullptr);
	vector<VkQueueFamilyProperties> queue_props(queue_count);
	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, queue_props.data());

	if (surface != VK_NULL_HANDLE)
	{
		VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceSurfaceSupportKHR);
	}

	bool found_queue = false;
	for (unsigned i = 0; i < queue_count; i++)
	{
		VkBool32 supported = surface == VK_NULL_HANDLE;
#ifdef HAVE_GLFW
		supported = glfwGetPhysicalDevicePresentationSupport(instance, gpu, i);
#else
		if (surface != VK_NULL_HANDLE)
			vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supported);
#endif

		VkQueueFlags required = VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT;
		if (supported && ((queue_props[i].queueFlags & required) == required))
		{
			found_queue = true;
			queue_family = i;
			break;
		}
	}

	if (!found_queue)
		return false;

	static const float prio = 1.0f;
	VkDeviceQueueCreateInfo queue_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };

	VkDeviceCreateInfo device_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
	device_info.pQueueCreateInfos = &queue_info;

	queue_info.queueFamilyIndex = queue_family;
	queue_info.queueCount = 1;
	queue_info.pQueuePriorities = &prio;
	device_info.queueCreateInfoCount = 1;

	// Should query for these, but no big deal for now.
	device_info.ppEnabledExtensionNames = required_device_extensions;
	device_info.enabledExtensionCount = num_required_device_extensions;
	device_info.ppEnabledLayerNames = required_device_layers;
	device_info.enabledLayerCount = num_required_device_layers;

	VkPhysicalDeviceFeatures enabled_features = *required_features;
	{
		VkPhysicalDeviceFeatures features;
		vkGetPhysicalDeviceFeatures(gpu, &features);
		if (features.textureCompressionETC2)
			enabled_features.textureCompressionETC2 = VK_TRUE;
		if (features.textureCompressionBC)
			enabled_features.textureCompressionBC = VK_TRUE;
		if (features.textureCompressionASTC_LDR)
			enabled_features.textureCompressionASTC_LDR = VK_TRUE;
		if (features.fullDrawIndexUint32)
			enabled_features.fullDrawIndexUint32 = VK_TRUE;
		if (features.imageCubeArray)
			enabled_features.imageCubeArray = VK_TRUE;
	}

	device_info.pEnabledFeatures = &enabled_features;

#ifdef VULKAN_DEBUG
	static const char *device_layers[] = { "VK_LAYER_LUNARG_standard_validation" };
	device_info.enabledLayerCount = 1;
	device_info.ppEnabledLayerNames = device_layers;
#endif

	if (vkCreateDevice(gpu, &device_info, nullptr, &device) != VK_SUCCESS)
		return false;

	vulkan_symbol_wrapper_load_core_device_symbols(device);
	vkGetDeviceQueue(device, queue_family, 0, &queue);
	return true;
}
}
<|endoftext|>


<commit_before>//
// PROJECT:         Aspia
// FILE:            ui/mru.cc
// LICENSE:         Mozilla Public License Version 2.0
// PROGRAMMERS:     Dmitry Chapyshev (dmitry@aspia.ru)
//

#include "base/files/base_paths.h"
#include "base/logging.h"
#include "codec/video_helpers.h"
#include "ui/mru.h"

#include <fstream>

namespace aspia {

namespace {

constexpr size_t kMaxMRUFileSize = 1024 * 1024; // 1 MB
constexpr size_t kMaxMRUItemCount = 30;

bool GetMRUFilePath(std::experimental::filesystem::path& path)
{
    if (!GetBasePath(BasePathKey::DIR_APP_DATA, path))
        return false;

    path.append(L"Aspia");
    path.append(L"mru.dat");

    return true;
}

bool ReadMRUFile(std::string& mru)
{
    std::experimental::filesystem::path file_path;

    if (!GetMRUFilePath(file_path))
        return false;

    std::ifstream file_stream;

    file_stream.open(file_path, std::ifstream::binary);
    if (!file_stream.is_open())
    {
        LOG(ERROR) << "File not found: " << file_path;
        return false;
    }

    file_stream.seekg(0, file_stream.end);
    std::streamoff size = static_cast<size_t>(file_stream.tellg());
    file_stream.seekg(0);

    if (!size)
        return false;

    if (size > kMaxMRUFileSize)
    {
        LOG(ERROR) << "MRU is too large (>1MB)";
        return false;
    }

    mru.resize(static_cast<size_t>(size));

    file_stream.read(mru.data(), size);

    if (file_stream.fail())
    {
        LOG(ERROR) << "Unable to read MRU";
        return false;
    }

    file_stream.close();

    return true;
}

bool WriteMRUFile(const std::string& mru)
{
    std::experimental::filesystem::path file_path;

    if (!GetMRUFilePath(file_path))
        return false;

    std::ofstream file_stream;

    file_stream.open(file_path, std::ofstream::binary);
    if (!file_stream.is_open())
    {
        LOG(ERROR) << "Unable to create (or open) file: " << file_path;
        return false;
    }

    file_stream.write(mru.c_str(), mru.size());
    if (file_stream.fail())
    {
        LOG(ERROR) << "Unable to write user list";
        return false;
    }

    file_stream.close();

    return true;
}

} // namespace

MRU::MRU()
{
    std::string string;

    if (!ReadMRUFile(string))
        return;

    if (!mru_.ParseFromString(string))
    {
        LOG(ERROR) << "Unable to parse MRU file";
        return;
    }

    if (mru_.client_config_size() > kMaxMRUItemCount)
    {
        mru_.mutable_client_config()->DeleteSubrange(
            0, mru_.client_config_size() - kMaxMRUFileSize);
    }
}

MRU::~MRU()
{
    WriteMRUFile(mru_.SerializeAsString());
}

// static
proto::ClientConfig MRU::GetDefaultConfig()
{
    proto::ClientConfig config;

    config.set_port(kDefaultHostTcpPort);
    config.set_session_type(proto::auth::SESSION_TYPE_DESKTOP_MANAGE);

    proto::desktop::Config* desktop_session_config = config.mutable_desktop_session();

    desktop_session_config->set_flags(proto::desktop::Config::ENABLE_CLIPBOARD |
                                      proto::desktop::Config::ENABLE_CURSOR_SHAPE);
    desktop_session_config->set_video_encoding(proto::desktop::VideoEncoding::VIDEO_ENCODING_ZLIB);
    desktop_session_config->set_update_interval(30);
    desktop_session_config->set_compress_ratio(6);

    ConvertToVideoPixelFormat(PixelFormat::RGB565(),
                              desktop_session_config->mutable_pixel_format());

    return config;
}

void MRU::AddItem(const proto::ClientConfig& client_config)
{
    if (client_config.address().empty())
        return;

    for (int index = 0; index < mru_.client_config_size(); ++index)
    {
        if (client_config.address() == mru_.client_config(index).address())
        {
            // Item already in the list. Remove from current position.
            mru_.mutable_client_config()->DeleteSubrange(index, 1);
            break;
        }
    }

    // Add item to end.
    mru_.add_client_config()->CopyFrom(client_config);

    if (mru_.client_config_size() > kMaxMRUItemCount)
    {
        // Remove first (oldest) item.
        mru_.mutable_client_config()->DeleteSubrange(0, 1);
    }
}

int MRU::GetItemCount() const
{
    return mru_.client_config_size();
}

const proto::ClientConfig& MRU::GetItem(int item_index) const
{
    DCHECK(mru_.client_config_size() != 0 && item_index < mru_.client_config_size());
    return mru_.client_config(item_index);
}

const proto::ClientConfig& MRU::SetLastItem(int item_index)
{
    DCHECK(mru_.client_config_size() != 0 && item_index < mru_.client_config_size());

    // Save item.
    proto::ClientConfig client_config = mru_.client_config(item_index);

    // Delete item from current position.
    mru_.mutable_client_config()->DeleteSubrange(item_index, 1);

    // Add item to end.
    mru_.add_client_config()->CopyFrom(client_config);

    // Get end item.
    return GetItem(GetItemCount() - 1);
}

} // namespace aspia
<commit_msg>- Reduce debug spam.<commit_after>//
// PROJECT:         Aspia
// FILE:            ui/mru.cc
// LICENSE:         Mozilla Public License Version 2.0
// PROGRAMMERS:     Dmitry Chapyshev (dmitry@aspia.ru)
//

#include "base/files/base_paths.h"
#include "base/logging.h"
#include "codec/video_helpers.h"
#include "ui/mru.h"

#include <fstream>

namespace aspia {

namespace {

constexpr size_t kMaxMRUFileSize = 1024 * 1024; // 1 MB
constexpr size_t kMaxMRUItemCount = 30;

bool GetMRUFilePath(std::experimental::filesystem::path& path)
{
    if (!GetBasePath(BasePathKey::DIR_APP_DATA, path))
        return false;

    path.append(L"Aspia");
    path.append(L"mru.dat");

    return true;
}

bool ReadMRUFile(std::string& mru)
{
    std::experimental::filesystem::path file_path;

    if (!GetMRUFilePath(file_path))
        return false;

    std::ifstream file_stream;

    file_stream.open(file_path, std::ifstream::binary);
    if (!file_stream.is_open())
    {
        DLOG(WARNING) << "File not found: " << file_path;
        return false;
    }

    file_stream.seekg(0, file_stream.end);
    std::streamoff size = static_cast<size_t>(file_stream.tellg());
    file_stream.seekg(0);

    if (!size)
        return false;

    if (size > kMaxMRUFileSize)
    {
        LOG(ERROR) << "MRU is too large (>1MB)";
        return false;
    }

    mru.resize(static_cast<size_t>(size));

    file_stream.read(mru.data(), size);

    if (file_stream.fail())
    {
        LOG(ERROR) << "Unable to read MRU";
        return false;
    }

    file_stream.close();

    return true;
}

bool WriteMRUFile(const std::string& mru)
{
    std::experimental::filesystem::path file_path;

    if (!GetMRUFilePath(file_path))
        return false;

    std::ofstream file_stream;

    file_stream.open(file_path, std::ofstream::binary);
    if (!file_stream.is_open())
    {
        LOG(ERROR) << "Unable to create (or open) file: " << file_path;
        return false;
    }

    file_stream.write(mru.c_str(), mru.size());
    if (file_stream.fail())
    {
        LOG(ERROR) << "Unable to write user list";
        return false;
    }

    file_stream.close();

    return true;
}

} // namespace

MRU::MRU()
{
    std::string string;

    if (!ReadMRUFile(string))
        return;

    if (!mru_.ParseFromString(string))
    {
        LOG(ERROR) << "Unable to parse MRU file";
        return;
    }

    if (mru_.client_config_size() > kMaxMRUItemCount)
    {
        mru_.mutable_client_config()->DeleteSubrange(
            0, mru_.client_config_size() - kMaxMRUFileSize);
    }
}

MRU::~MRU()
{
    WriteMRUFile(mru_.SerializeAsString());
}

// static
proto::ClientConfig MRU::GetDefaultConfig()
{
    proto::ClientConfig config;

    config.set_port(kDefaultHostTcpPort);
    config.set_session_type(proto::auth::SESSION_TYPE_DESKTOP_MANAGE);

    proto::desktop::Config* desktop_session_config = config.mutable_desktop_session();

    desktop_session_config->set_flags(proto::desktop::Config::ENABLE_CLIPBOARD |
                                      proto::desktop::Config::ENABLE_CURSOR_SHAPE);
    desktop_session_config->set_video_encoding(proto::desktop::VideoEncoding::VIDEO_ENCODING_ZLIB);
    desktop_session_config->set_update_interval(30);
    desktop_session_config->set_compress_ratio(6);

    ConvertToVideoPixelFormat(PixelFormat::RGB565(),
                              desktop_session_config->mutable_pixel_format());

    return config;
}

void MRU::AddItem(const proto::ClientConfig& client_config)
{
    if (client_config.address().empty())
        return;

    for (int index = 0; index < mru_.client_config_size(); ++index)
    {
        if (client_config.address() == mru_.client_config(index).address())
        {
            // Item already in the list. Remove from current position.
            mru_.mutable_client_config()->DeleteSubrange(index, 1);
            break;
        }
    }

    // Add item to end.
    mru_.add_client_config()->CopyFrom(client_config);

    if (mru_.client_config_size() > kMaxMRUItemCount)
    {
        // Remove first (oldest) item.
        mru_.mutable_client_config()->DeleteSubrange(0, 1);
    }
}

int MRU::GetItemCount() const
{
    return mru_.client_config_size();
}

const proto::ClientConfig& MRU::GetItem(int item_index) const
{
    DCHECK(mru_.client_config_size() != 0 && item_index < mru_.client_config_size());
    return mru_.client_config(item_index);
}

const proto::ClientConfig& MRU::SetLastItem(int item_index)
{
    DCHECK(mru_.client_config_size() != 0 && item_index < mru_.client_config_size());

    // Save item.
    proto::ClientConfig client_config = mru_.client_config(item_index);

    // Delete item from current position.
    mru_.mutable_client_config()->DeleteSubrange(item_index, 1);

    // Add item to end.
    mru_.add_client_config()->CopyFrom(client_config);

    // Get end item.
    return GetItem(GetItemCount() - 1);
}

} // namespace aspia
<|endoftext|>