<commit_before>#ifndef ___GFTOOLS_ENUMERATEGRID_HPP___
#define ___GFTOOLS_ENUMERATEGRID_HPP___

#include "grid_base.hpp"

namespace gftools {

// A wrapper around int to avoid weird gcc bug
struct int_wrap_enumerate_grid
{
    int v_;
    operator int() const{return v_;};
    explicit operator double() { return double(v_);};
    operator int&(){return v_;};
    int_wrap_enumerate_grid(int i=0):v_(i) {};
};

/** A grid of real values. */
class enum_grid : public grid_base<int_wrap_enumerate_grid, enum_grid>
{
public:
    typedef grid_base<int_wrap_enumerate_grid, enum_grid> base;
    template <class Obj> auto integrate(const Obj &in) const ->decltype(in(vals_[0]));
    template <class Obj, typename ...OtherArgTypes> auto integrate(const Obj &in, OtherArgTypes... Args) const -> decltype(in(vals_[0],Args...));
    /** Generates a uniform grid.
     * \param[in] min Minimal point
     * \param[in] max Maximal point
     * \param[in] npoints Number of points
     * \param[in] include_last True, if the max point needs to be included
     */
    enum_grid(int min, int max, bool include_last = false);
    enum_grid(const std::vector<int>& in):base( ([&in](){std::vector<typename point::value_type> out(in.size()); for (int i=0; i<out.size(); ++i) out[i]=in[i]; return out; })()) {}
    enum_grid(enum_grid&& rhs);
    enum_grid(const enum_grid& rhs):base(rhs){}
    enum_grid& operator=(enum_grid &&rhs);
    std::tuple <bool, size_t, int> find (int in) const ;
    //template <class Obj> auto gridIntegrate(std::vector<Obj> &in) -> Obj;
    template <class Obj> auto eval(Obj &in, enum_grid::point x) const -> decltype(in[0]);
    template <class Obj> auto eval(Obj &in, int x) const -> decltype(std::declval<typename std::remove_reference<decltype(in[0])>::type>()*1.0);
    //template <class Obj> auto eval(Obj &in, EnumerateGrid::point x) const ->decltype(in[0]);
};

//
// enum_grid implementation
//

inline enum_grid::enum_grid(int min, int max, bool include_last):
grid_base<int_wrap_enumerate_grid, enum_grid>(min,max+include_last,[](int n){return n;})
{
}

enum_grid::enum_grid(enum_grid&& rhs):
    base(std::forward<base>(rhs))
{
};

enum_grid& enum_grid::operator=(enum_grid &&rhs)
{
    base(*this) = base(rhs);
    return (*this);
};

inline std::tuple<bool, size_t, int> enum_grid::find (int in) const
{
    if (in<vals_[0].val_) { ERROR("out of bounds"); return std::make_tuple(0,0,0);};
    if (in > vals_[vals_.size()-1].val_) { ERROR("out of bounds"); return std::make_tuple(0,vals_.size(),0);};
    return std::make_tuple (1,in-vals_[0].val_,1);
}

template <class Obj>
inline auto enum_grid::eval(Obj &in, int x) const ->
    decltype(std::declval<typename std::remove_reference<decltype(in[0])>::type>()*1.0)
{
    const auto find_result=this->find(x);
    if (!std::get<0>(find_result)) { throw (std::logic_error("Wrong index")); }
    return in[std::get<1>(find_result)];
}

template <class Obj>
inline auto enum_grid::eval(Obj &in, enum_grid::point x) const ->decltype(in[0])
{
    if (x.index_ < vals_.size() && x == vals_[x.index_])
    return in[x.index_];
    else {
        #ifndef NDEBUG
        ERROR ("Point not found");
        #endif
        return this->eval(in, int(x));
         };
}

} // end of namespace gftools
#endif // endif :: #ifndef ___GFTOOLS_REALGRID_HPP___
<commit_msg>inline constructors in enum_grid<commit_after>#ifndef ___GFTOOLS_ENUMERATEGRID_HPP___
#define ___GFTOOLS_ENUMERATEGRID_HPP___

#include "grid_base.hpp"

namespace gftools {

// A wrapper around int to avoid weird gcc bug
struct int_wrap_enumerate_grid
{
    int v_;
    operator int() const{return v_;};
    explicit operator double() { return double(v_);};
    operator int&(){return v_;};
    int_wrap_enumerate_grid(int i=0):v_(i) {};
};

/** A grid of real values. */
class enum_grid : public grid_base<int_wrap_enumerate_grid, enum_grid>
{
public:
    typedef grid_base<int_wrap_enumerate_grid, enum_grid> base;
    template <class Obj> auto integrate(const Obj &in) const ->decltype(in(vals_[0]));
    template <class Obj, typename ...OtherArgTypes> auto integrate(const Obj &in, OtherArgTypes... Args) const -> decltype(in(vals_[0],Args...));
    /** Generates a uniform grid.
     * \param[in] min Minimal point
     * \param[in] max Maximal point
     * \param[in] npoints Number of points
     * \param[in] include_last True, if the max point needs to be included
     */
    enum_grid(int min, int max, bool include_last = false);
    enum_grid(const std::vector<int>& in):base( ([&in](){std::vector<typename point::value_type> out(in.size()); for (int i=0; i<out.size(); ++i) out[i]=in[i]; return out; })()) {}
    enum_grid(enum_grid&& rhs);
    enum_grid(const enum_grid& rhs):base(rhs){}
    enum_grid& operator=(enum_grid &&rhs);
    std::tuple <bool, size_t, int> find (int in) const ;
    //template <class Obj> auto gridIntegrate(std::vector<Obj> &in) -> Obj;
    template <class Obj> auto eval(Obj &in, enum_grid::point x) const -> decltype(in[0]);
    template <class Obj> auto eval(Obj &in, int x) const -> decltype(std::declval<typename std::remove_reference<decltype(in[0])>::type>()*1.0);
    //template <class Obj> auto eval(Obj &in, EnumerateGrid::point x) const ->decltype(in[0]);
};

//
// enum_grid implementation
//

inline enum_grid::enum_grid(int min, int max, bool include_last):
grid_base<int_wrap_enumerate_grid, enum_grid>(min,max+include_last,[](int n){return n;})
{
}

inline enum_grid::enum_grid(enum_grid&& rhs):
    base(std::forward<base>(rhs))
{
};

inline enum_grid& enum_grid::operator=(enum_grid &&rhs)
{
    base(*this) = base(rhs);
    return (*this);
};

inline std::tuple<bool, size_t, int> enum_grid::find (int in) const
{
    if (in<vals_[0].val_) { ERROR("out of bounds"); return std::make_tuple(0,0,0);};
    if (in > vals_[vals_.size()-1].val_) { ERROR("out of bounds"); return std::make_tuple(0,vals_.size(),0);};
    return std::make_tuple (1,in-vals_[0].val_,1);
}

template <class Obj>
inline auto enum_grid::eval(Obj &in, int x) const ->
    decltype(std::declval<typename std::remove_reference<decltype(in[0])>::type>()*1.0)
{
    const auto find_result=this->find(x);
    if (!std::get<0>(find_result)) { throw (std::logic_error("Wrong index")); }
    return in[std::get<1>(find_result)];
}

template <class Obj>
inline auto enum_grid::eval(Obj &in, enum_grid::point x) const ->decltype(in[0])
{
    if (x.index_ < vals_.size() && x == vals_[x.index_])
    return in[x.index_];
    else {
        #ifndef NDEBUG
        ERROR ("Point not found");
        #endif
        return this->eval(in, int(x));
         };
}

} // end of namespace gftools
#endif // endif :: #ifndef ___GFTOOLS_REALGRID_HPP___
<|endoftext|>


<commit_before>/*
 * datasettree.cpp
 *
 *  Created on: 17.09.2013
 *      Author: Ralph
 */

#include "datasettree.h"

#include "../../gui/gl/colormapfunctions.h"
#include "../../gui/gl/treerenderer.h"
#include "../../algos/colormapbase.h"

#include "../../algos/tree.h"

#include <QDebug>

DatasetTree::DatasetTree( QDir fn ) :
    Dataset( fn , Fn::DatasetType::TREE ),
    m_tree( 0 ),
    m_renderer( 0 ),
    m_numLeaves( 0 ),
    m_numNodes( 0 )
{
    m_properties["maingl"]->create( Fn::Property::D_COLORMAP, -1 );
    m_properties["maingl"]->create( Fn::Property::D_INTERPOLATION, false );
    m_properties["maingl"]->create( Fn::Property::D_ALPHA, 1.0f, 0.0, 1.0 );
    m_properties["maingl"]->create( Fn::Property::D_DIM, 3 );

    m_properties["maingl"]->create( Fn::Property::D_TREE_SELECTED_CLUSTER, 0, 0, 0, "general" );
    connect( m_properties["maingl"]->getProperty( Fn::Property::D_TREE_SELECTED_CLUSTER ), SIGNAL( valueChanged( QVariant ) ), this, SLOT( selectCluster( QVariant ) ) );
    m_properties["maingl"]->create( Fn::Property::D_TREE_SELECTED_CLUSTER_COLOR, QColor( 255, 0, 0 ), "general" );
    m_properties["maingl"]->create( Fn::Property::D_TREE_UNSELECTED_CLUSTER_COLOR, QColor( 128, 128, 128 ), "general" );

    PropertyGroup* props2 = new PropertyGroup( *( m_properties["maingl"] ) );
    m_properties.insert( "maingl2", props2 );
    m_properties["maingl2"]->getProperty( Fn::Property::D_ACTIVE )->setPropertyTab( "general" );

}

DatasetTree::~DatasetTree()
{
}

void DatasetTree::draw( QMatrix4x4 pMatrix, QMatrix4x4 mvMatrix, int width, int height, int renderMode, QString target )
{

}

void DatasetTree::drawTree( QMatrix4x4 mvpMatrix, int width, int height )
{
    m_width = width;
    m_height = height;

    if ( m_renderer == 0 )
    {
        m_renderer = new TreeRenderer( "tree", m_tree );
        m_renderer->init();
    }
    m_renderer->draw( mvpMatrix );
}

void DatasetTree::importTree( QString dims, QVector<QString>coords, QVector<QString>clusters )
{
    QStringList dl = dims.split( " " );

    m_properties["maingl"]->create( Fn::Property::D_NX, dl[0].toInt() );
    m_properties["maingl"]->create( Fn::Property::D_NY, dl[1].toInt() );
    m_properties["maingl"]->create( Fn::Property::D_NZ, dl[2].toInt() );
    m_properties["maingl"]->create( Fn::Property::D_DX, 1.0f );
    m_properties["maingl"]->create( Fn::Property::D_DY, 1.0f );
    m_properties["maingl"]->create( Fn::Property::D_DZ, 1.0f );

    QVector<Tree*>nodes;
    QVector<Tree*>leaves( coords.size() );

    m_numLeaves = coords.size();
    m_numNodes = clusters.size();

    m_properties["maingl"]->setMax( Fn::Property::D_TREE_SELECTED_CLUSTER, m_numLeaves + m_numNodes );

    qDebug() << "num leaves:" << m_numLeaves << "num nodes:" << m_numNodes;

    int currentId = coords.size();

    ColormapBase cmap = ColormapFunctions::getColormap( 2 );

    for( int i = 0; i < clusters.size(); ++i )
    {
        QStringList cl = clusters[i].split( " " );
        float value = cl[0].toFloat();

        m_tree = new Tree( currentId++, value );

        nodes.push_back( m_tree );

        for ( int k = 1; k < cl.size(); k += 2 )
        {
            bool isNode = cl[k].toInt();
            int id = cl[k+1].toInt();
            if( isNode )
            {
                if( id < nodes.size() )
                {
                    nodes[id]->setParent( m_tree );
                    m_tree->addChild( nodes[id] );
                }
                else
                {
                    qDebug() << "node id error";
                }
            }
            else
            {
                Tree* leaf = new Tree( id, 0.0 );
                leaf->setParent( m_tree );
                m_tree->addChild( leaf );

                QStringList cList = coords[id].split( " " );
                QVector3D pos( cList[0].toInt(), cList[1].toInt(), cList[2].toInt() );
                leaf->setTexturePosition( pos );
                leaves[id] = leaf;
            }
        }
    }

    for( int i = 0; i < leaves.size(); ++i )
    {
        float v = ( (float)i/(float)m_numLeaves );
        QColor c = cmap.getColor( qMax( 0.0f, qMin( 1.0f, v ) ) );
        leaves[i]->setColor( 0, c, true, false );
    }

    nodes.clear();
    leaves.clear();
    qDebug() << "test num leaves:" << m_tree->getNumLeaves();

    createTexture();
    m_properties["maingl"]->set( Fn::Property::D_HAS_TEXTURE, true );
}

void DatasetTree::createTexture()
{
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );

    glGenTextures( 1, &m_textureGLuint );

    glBindTexture( GL_TEXTURE_3D, m_textureGLuint );

    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP );

    int nx = m_properties["maingl"]->get( Fn::Property::D_NX ).toInt();
    int ny = m_properties["maingl"]->get( Fn::Property::D_NY ).toInt();
    int nz = m_properties["maingl"]->get( Fn::Property::D_NZ ).toInt();

    int blockSize = nx * ny * nz;
    m_textureData.resize( blockSize * 3 );
    for ( int i = 0; i < blockSize * 3; ++i )
    {
        m_textureData[i] = 0.0;
    }

    createTextureRec( m_tree );

    glTexImage3D( GL_TEXTURE_3D, 0, GL_RGBA, nx, ny, nz, 0, GL_RGB, GL_FLOAT, m_textureData.data() );
}

void DatasetTree::createTextureRec( Tree* tree )
{
    QList<Tree*>children = tree->getChildren();
    if ( children.size() > 0 )
    {
        for( int i = 0; i < children.size(); ++i )
        {
            createTextureRec( children[i] );
        }
    }
    else
    {
        int nx = m_properties["maingl"]->get( Fn::Property::D_NX ).toInt();
        int ny = m_properties["maingl"]->get( Fn::Property::D_NY ).toInt();
        //int nz = m_properties["maingl"]->get( Fn::Property::D_NZ ).toInt();

        QVector3D pos = tree->getTexturePosition();
        QColor color = tree->getColor( 0 );

        int id = ( pos.x() + pos.y() * nx + pos.z() * nx * ny ) * 3;

        m_textureData[id] = color.redF();
        m_textureData[id+1] = color.greenF();
        m_textureData[id+2] = color.blueF();
    }
}

void DatasetTree::selectCluster( QVariant id )
{
    QColor unselectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_UNSELECTED_CLUSTER_COLOR ).value<QColor>();
    QColor selectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_SELECTED_CLUSTER_COLOR ).value<QColor>();
    m_tree->setColor( 0, unselectedColor , false, true );
    m_tree->setColor( id.toInt(), 0, selectedColor );

    m_renderer->update();
}

bool DatasetTree::mousePick( int pickId, QVector3D pos, Qt::KeyboardModifiers modifiers, QString target )
{
    if( target != "tree" )
    {
        return false;
    }
    float x = ( pos.x() / static_cast<float>( m_width ) ) * m_numLeaves;
    float y = 1.0 - ( pos.y() / static_cast<float>( m_height ) );
    qDebug() << x << y ;
    int id = pickClusterRec( m_tree, m_width, m_height, x, y );
    qDebug() << id;
    if ( id != -1 )
    {
        m_properties["maingl"]->set( Fn::Property::D_TREE_SELECTED_CLUSTER, id );
        QColor unselectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_UNSELECTED_CLUSTER_COLOR ).value<QColor>();
        QColor selectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_SELECTED_CLUSTER_COLOR ).value<QColor>();
        m_tree->setColor( 0, unselectedColor , false, true );
        m_tree->setColor( id, 0, selectedColor );
        m_renderer->update();
    }
    return true;
}

int DatasetTree::pickClusterRec( Tree* tree, int left, int right, float x, float y )
{
    if ( ( tree->getValue() > ( y - 0.01 ) ) && ( tree->getValue() < ( y + 0.01 ) ) )
    {
        if( x > left && x < right )
        {
            return tree->getId();
        }
    }
    else
    {
        QList<Tree*> children = tree->getChildren();

        int offset = 0;
        for ( int i = 0; i < children.size(); ++i )
        {
            Tree* child = children[i];

            int size = child->getNumLeaves();

            int id = pickClusterRec( child, left + offset, left + offset + size, x, y );
            if( id != -1 )
            {
                return id;
            }

            offset += size;
        }
    }
    return -1;
}
<commit_msg>fixed cluster picking<commit_after>/*
 * datasettree.cpp
 *
 *  Created on: 17.09.2013
 *      Author: Ralph
 */

#include "datasettree.h"

#include "../../gui/gl/colormapfunctions.h"
#include "../../gui/gl/treerenderer.h"
#include "../../algos/colormapbase.h"

#include "../../algos/tree.h"

#include <QDebug>

DatasetTree::DatasetTree( QDir fn ) :
    Dataset( fn , Fn::DatasetType::TREE ),
    m_tree( 0 ),
    m_renderer( 0 ),
    m_numLeaves( 0 ),
    m_numNodes( 0 )
{
    m_properties["maingl"]->create( Fn::Property::D_COLORMAP, -1 );
    m_properties["maingl"]->create( Fn::Property::D_INTERPOLATION, false );
    m_properties["maingl"]->create( Fn::Property::D_ALPHA, 1.0f, 0.0, 1.0 );
    m_properties["maingl"]->create( Fn::Property::D_DIM, 3 );

    m_properties["maingl"]->create( Fn::Property::D_TREE_SELECTED_CLUSTER, 0, 0, 0, "general" );
    connect( m_properties["maingl"]->getProperty( Fn::Property::D_TREE_SELECTED_CLUSTER ), SIGNAL( valueChanged( QVariant ) ), this, SLOT( selectCluster( QVariant ) ) );
    m_properties["maingl"]->create( Fn::Property::D_TREE_SELECTED_CLUSTER_COLOR, QColor( 255, 0, 0 ), "general" );
    m_properties["maingl"]->create( Fn::Property::D_TREE_UNSELECTED_CLUSTER_COLOR, QColor( 128, 128, 128 ), "general" );

    PropertyGroup* props2 = new PropertyGroup( *( m_properties["maingl"] ) );
    m_properties.insert( "maingl2", props2 );
    m_properties["maingl2"]->getProperty( Fn::Property::D_ACTIVE )->setPropertyTab( "general" );

}

DatasetTree::~DatasetTree()
{
}

void DatasetTree::draw( QMatrix4x4 pMatrix, QMatrix4x4 mvMatrix, int width, int height, int renderMode, QString target )
{

}

void DatasetTree::drawTree( QMatrix4x4 mvpMatrix, int width, int height )
{
    m_width = width;
    m_height = height;

    if ( m_renderer == 0 )
    {
        m_renderer = new TreeRenderer( "tree", m_tree );
        m_renderer->init();
    }
    m_renderer->draw( mvpMatrix );
}

void DatasetTree::importTree( QString dims, QVector<QString>coords, QVector<QString>clusters )
{
    QStringList dl = dims.split( " " );

    m_properties["maingl"]->create( Fn::Property::D_NX, dl[0].toInt() );
    m_properties["maingl"]->create( Fn::Property::D_NY, dl[1].toInt() );
    m_properties["maingl"]->create( Fn::Property::D_NZ, dl[2].toInt() );
    m_properties["maingl"]->create( Fn::Property::D_DX, 1.0f );
    m_properties["maingl"]->create( Fn::Property::D_DY, 1.0f );
    m_properties["maingl"]->create( Fn::Property::D_DZ, 1.0f );

    QVector<Tree*>nodes;
    QVector<Tree*>leaves( coords.size() );

    m_numLeaves = coords.size();
    m_numNodes = clusters.size();

    m_properties["maingl"]->setMax( Fn::Property::D_TREE_SELECTED_CLUSTER, m_numLeaves + m_numNodes );

    qDebug() << "num leaves:" << m_numLeaves << "num nodes:" << m_numNodes;

    int currentId = coords.size();

    ColormapBase cmap = ColormapFunctions::getColormap( 2 );

    for( int i = 0; i < clusters.size(); ++i )
    {
        QStringList cl = clusters[i].split( " " );
        float value = cl[0].toFloat();

        m_tree = new Tree( currentId++, value );

        nodes.push_back( m_tree );

        for ( int k = 1; k < cl.size(); k += 2 )
        {
            bool isNode = cl[k].toInt();
            int id = cl[k+1].toInt();
            if( isNode )
            {
                if( id < nodes.size() )
                {
                    nodes[id]->setParent( m_tree );
                    m_tree->addChild( nodes[id] );
                }
                else
                {
                    qDebug() << "node id error";
                }
            }
            else
            {
                Tree* leaf = new Tree( id, 0.0 );
                leaf->setParent( m_tree );
                m_tree->addChild( leaf );

                QStringList cList = coords[id].split( " " );
                QVector3D pos( cList[0].toInt(), cList[1].toInt(), cList[2].toInt() );
                leaf->setTexturePosition( pos );
                leaves[id] = leaf;
            }
        }
    }

    for( int i = 0; i < leaves.size(); ++i )
    {
        float v = ( (float)i/(float)m_numLeaves );
        QColor c = cmap.getColor( qMax( 0.0f, qMin( 1.0f, v ) ) );
        leaves[i]->setColor( 0, c, true, false );
    }

    nodes.clear();
    leaves.clear();
    qDebug() << "test num leaves:" << m_tree->getNumLeaves();

    createTexture();
    m_properties["maingl"]->set( Fn::Property::D_HAS_TEXTURE, true );
}

void DatasetTree::createTexture()
{
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );

    glGenTextures( 1, &m_textureGLuint );

    glBindTexture( GL_TEXTURE_3D, m_textureGLuint );

    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP );

    int nx = m_properties["maingl"]->get( Fn::Property::D_NX ).toInt();
    int ny = m_properties["maingl"]->get( Fn::Property::D_NY ).toInt();
    int nz = m_properties["maingl"]->get( Fn::Property::D_NZ ).toInt();

    int blockSize = nx * ny * nz;
    m_textureData.resize( blockSize * 3 );
    for ( int i = 0; i < blockSize * 3; ++i )
    {
        m_textureData[i] = 0.0;
    }

    createTextureRec( m_tree );

    glTexImage3D( GL_TEXTURE_3D, 0, GL_RGBA, nx, ny, nz, 0, GL_RGB, GL_FLOAT, m_textureData.data() );
}

void DatasetTree::createTextureRec( Tree* tree )
{
    QList<Tree*>children = tree->getChildren();
    if ( children.size() > 0 )
    {
        for( int i = 0; i < children.size(); ++i )
        {
            createTextureRec( children[i] );
        }
    }
    else
    {
        int nx = m_properties["maingl"]->get( Fn::Property::D_NX ).toInt();
        int ny = m_properties["maingl"]->get( Fn::Property::D_NY ).toInt();
        //int nz = m_properties["maingl"]->get( Fn::Property::D_NZ ).toInt();

        QVector3D pos = tree->getTexturePosition();
        QColor color = tree->getColor( 0 );

        int id = ( pos.x() + pos.y() * nx + pos.z() * nx * ny ) * 3;

        m_textureData[id] = color.redF();
        m_textureData[id+1] = color.greenF();
        m_textureData[id+2] = color.blueF();
    }
}

void DatasetTree::selectCluster( QVariant id )
{
    QColor unselectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_UNSELECTED_CLUSTER_COLOR ).value<QColor>();
    QColor selectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_SELECTED_CLUSTER_COLOR ).value<QColor>();
    m_tree->setColor( 0, unselectedColor , false, true );
    m_tree->setColor( id.toInt(), 0, selectedColor );

    m_renderer->update();
}

bool DatasetTree::mousePick( int pickId, QVector3D pos, Qt::KeyboardModifiers modifiers, QString target )
{
    if( target != "tree" )
    {
        return false;
    }
    float x = ( pos.x() / static_cast<float>( m_width ) ) * m_numLeaves;
    float y = 1.0 - ( pos.y() / static_cast<float>( m_height ) );
    qDebug() << x << y ;
    int id = pickClusterRec( m_tree, 0, m_width * m_numLeaves, x, y );
    qDebug() << id;
    if ( id != -1 )
    {
        m_properties["maingl"]->set( Fn::Property::D_TREE_SELECTED_CLUSTER, id );
        QColor unselectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_UNSELECTED_CLUSTER_COLOR ).value<QColor>();
        QColor selectedColor = m_properties["maingl"]->get( Fn::Property::D_TREE_SELECTED_CLUSTER_COLOR ).value<QColor>();
        m_tree->setColor( 0, unselectedColor , false, true );
        m_tree->setColor( id, 0, selectedColor );
        m_renderer->update();
    }
    return true;
}

int DatasetTree::pickClusterRec( Tree* tree, int left, int right, float x, float y )
{
    if ( ( tree->getValue() > ( y - 0.01 ) ) && ( tree->getValue() < ( y + 0.01 ) ) )
    {
        if( x > left && x < right )
        {
            return tree->getId();
        }
    }
    else
    {
        QList<Tree*> children = tree->getChildren();

        int offset = 0;
        for ( int i = 0; i < children.size(); ++i )
        {
            Tree* child = children[i];

            int size = child->getNumLeaves();

            int id = pickClusterRec( child, left + offset, left + offset + size, x, y );
            if( id != -1 )
            {
                return id;
            }

            offset += size;
        }
    }
    return -1;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <support/lockedpool.h>
#include <support/cleanse.h>

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <sys/mman.h> // for mmap
#include <sys/resource.h> // for getrlimit
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

#include <algorithm>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
#endif

LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;

/*******************************************************************************/
// Utilities
//
/** Align up to power of 2 */
static inline size_t align_up(size_t x, size_t align)
{
    return (x + align - 1) & ~(align - 1);
}

/*******************************************************************************/
// Implementation: Arena

Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
    base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
    // Start with one free chunk that covers the entire arena
    auto it = size_to_free_chunk.emplace(size_in, base);
    chunks_free.emplace(base, it);
    chunks_free_end.emplace(base + size_in, it);
}

Arena::~Arena()
{
}

void* Arena::alloc(size_t size)
{
    // Round to next multiple of alignment
    size = align_up(size, alignment);

    // Don't handle zero-sized chunks
    if (size == 0)
        return nullptr;

    // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
    // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
    // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
    // policies seem to work well in practice.
    auto size_ptr_it = size_to_free_chunk.lower_bound(size);
    if (size_ptr_it == size_to_free_chunk.end())
        return nullptr;

    // Create the used-chunk, taking its space from the end of the free-chunk
    const size_t size_remaining = size_ptr_it->first - size;
    auto allocated = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
    chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
    if (size_ptr_it->first == size) {
        // whole chunk is used up
        chunks_free.erase(size_ptr_it->second);
    } else {
        // still some memory left in the chunk
        auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
        chunks_free[size_ptr_it->second] = it_remaining;
        chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
    }
    size_to_free_chunk.erase(size_ptr_it);

    return reinterpret_cast<void*>(allocated->first);
}

void Arena::free(void *ptr)
{
    // Freeing the nullptr pointer is OK.
    if (ptr == nullptr) {
        return;
    }

    // Remove chunk from used map
    auto i = chunks_used.find(static_cast<char*>(ptr));
    if (i == chunks_used.end()) {
        throw std::runtime_error("Arena: invalid or double free");
    }
    std::pair<char*, size_t> freed = *i;
    chunks_used.erase(i);

    // coalesce freed with previous chunk
    auto prev = chunks_free_end.find(freed.first);
    if (prev != chunks_free_end.end()) {
        freed.first -= prev->second->first;
        freed.second += prev->second->first;
        size_to_free_chunk.erase(prev->second);
        chunks_free_end.erase(prev);
    }

    // coalesce freed with chunk after freed
    auto next = chunks_free.find(freed.first + freed.second);
    if (next != chunks_free.end()) {
        freed.second += next->second->first;
        size_to_free_chunk.erase(next->second);
        chunks_free.erase(next);
    }

    // Add/set space with coalesced free chunk
    auto it = size_to_free_chunk.emplace(freed.second, freed.first);
    chunks_free[freed.first] = it;
    chunks_free_end[freed.first + freed.second] = it;
}

Arena::Stats Arena::stats() const
{
    Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
    for (const auto& chunk: chunks_used)
        r.used += chunk.second;
    for (const auto& chunk: chunks_free)
        r.free += chunk.second->first;
    r.total = r.used + r.free;
    return r;
}

#ifdef ARENA_DEBUG
static void printchunk(void* base, size_t sz, bool used) {
    std::cout <<
        "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
        " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
        " 0x" << used << std::endl;
}
void Arena::walk() const
{
    for (const auto& chunk: chunks_used)
        printchunk(chunk.first, chunk.second, true);
    std::cout << std::endl;
    for (const auto& chunk: chunks_free)
        printchunk(chunk.first, chunk.second->first, false);
    std::cout << std::endl;
}
#endif

/*******************************************************************************/
// Implementation: Win32LockedPageAllocator

#ifdef WIN32
/** LockedPageAllocator specialized for Windows.
 */
class Win32LockedPageAllocator: public LockedPageAllocator
{
public:
    Win32LockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

Win32LockedPageAllocator::Win32LockedPageAllocator()
{
    // Determine system page size in bytes
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
}
void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    len = align_up(len, page_size);
    void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (addr) {
        // VirtualLock is used to attempt to keep keying material out of swap. Note
        // that it does not provide this as a guarantee, but, in practice, memory
        // that has been VirtualLock'd almost never gets written to the pagefile
        // except in rare circumstances where memory is extremely low.
        *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
    }
    return addr;
}
void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    VirtualUnlock(const_cast<void*>(addr), len);
}

size_t Win32LockedPageAllocator::GetLimit()
{
    // TODO is there a limit on Windows, how to get it?
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: PosixLockedPageAllocator

#ifndef WIN32
/** LockedPageAllocator specialized for OSes that don't try to be
 * special snowflakes.
 */
class PosixLockedPageAllocator: public LockedPageAllocator
{
public:
    PosixLockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

PosixLockedPageAllocator::PosixLockedPageAllocator()
{
    // Determine system page size in bytes
#if defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else                   // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
}

// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
// MAP_ANON which is deprecated
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    void *addr;
    len = align_up(len, page_size);
    addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        return nullptr;
    }
    if (addr) {
        *lockingSuccess = mlock(addr, len) == 0;
#ifdef MADV_DONTDUMP
        madvise(addr, len, MADV_DONTDUMP);
#endif
    }
    return addr;
}
void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    munlock(addr, len);
    munmap(addr, len);
}
size_t PosixLockedPageAllocator::GetLimit()
{
#ifdef RLIMIT_MEMLOCK
    struct rlimit rlim;
    if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
        if (rlim.rlim_cur != RLIM_INFINITY) {
            return rlim.rlim_cur;
        }
    }
#endif
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: LockedPool

LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
    allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
{
}

LockedPool::~LockedPool()
{
}
void* LockedPool::alloc(size_t size)
{
    std::lock_guard<std::mutex> lock(mutex);

    // Don't handle impossible sizes
    if (size == 0 || size > ARENA_SIZE)
        return nullptr;

    // Try allocating from each current arena
    for (auto &arena: arenas) {
        void *addr = arena.alloc(size);
        if (addr) {
            return addr;
        }
    }
    // If that fails, create a new one
    if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
        return arenas.back().alloc(size);
    }
    return nullptr;
}

void LockedPool::free(void *ptr)
{
    std::lock_guard<std::mutex> lock(mutex);
    // TODO we can do better than this linear search by keeping a map of arena
    // extents to arena, and looking up the address.
    for (auto &arena: arenas) {
        if (arena.addressInArena(ptr)) {
            arena.free(ptr);
            return;
        }
    }
    throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
}

LockedPool::Stats LockedPool::stats() const
{
    std::lock_guard<std::mutex> lock(mutex);
    LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
    for (const auto &arena: arenas) {
        Arena::Stats i = arena.stats();
        r.used += i.used;
        r.free += i.free;
        r.total += i.total;
        r.chunks_used += i.chunks_used;
        r.chunks_free += i.chunks_free;
    }
    return r;
}

bool LockedPool::new_arena(size_t size, size_t align)
{
    bool locked;
    // If this is the first arena, handle this specially: Cap the upper size
    // by the process limit. This makes sure that the first arena will at least
    // be locked. An exception to this is if the process limit is 0:
    // in this case no memory can be locked at all so we'll skip past this logic.
    if (arenas.empty()) {
        size_t limit = allocator->GetLimit();
        if (limit > 0) {
            size = std::min(size, limit);
        }
    }
    void *addr = allocator->AllocateLocked(size, &locked);
    if (!addr) {
        return false;
    }
    if (locked) {
        cumulative_bytes_locked += size;
    } else if (lf_cb) { // Call the locking-failed callback if locking failed
        if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
            allocator->FreeLocked(addr, size);
            return false;
        }
    }
    arenas.emplace_back(allocator.get(), addr, size, align);
    return true;
}

LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
    Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
{
}
LockedPool::LockedPageArena::~LockedPageArena()
{
    allocator->FreeLocked(base, size);
}

/*******************************************************************************/
// Implementation: LockedPoolManager
//
LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):
    LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)
{
}

bool LockedPoolManager::LockingFailed()
{
    // TODO: log something but how? without including util.h
    return true;
}

void LockedPoolManager::CreateInstance()
{
    // Using a local static instance guarantees that the object is initialized
    // when it's first needed and also deinitialized after all objects that use
    // it are done with it.  I can think of one unlikely scenario where we may
    // have a static deinitialization order/problem, but the check in
    // LockedPoolManagerBase's destructor helps us detect if that ever happens.
#ifdef WIN32
    std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
#else
    std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
#endif
    static LockedPoolManager instance(std::move(allocator));
    LockedPoolManager::_instance = &instance;
}
<commit_msg>lockedpool: avoid sensitive data in core files (FreeBSD)<commit_after>// Copyright (c) 2016-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <support/lockedpool.h>
#include <support/cleanse.h>

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <sys/mman.h> // for mmap
#include <sys/resource.h> // for getrlimit
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

#include <algorithm>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
#endif

LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;

/*******************************************************************************/
// Utilities
//
/** Align up to power of 2 */
static inline size_t align_up(size_t x, size_t align)
{
    return (x + align - 1) & ~(align - 1);
}

/*******************************************************************************/
// Implementation: Arena

Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
    base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
    // Start with one free chunk that covers the entire arena
    auto it = size_to_free_chunk.emplace(size_in, base);
    chunks_free.emplace(base, it);
    chunks_free_end.emplace(base + size_in, it);
}

Arena::~Arena()
{
}

void* Arena::alloc(size_t size)
{
    // Round to next multiple of alignment
    size = align_up(size, alignment);

    // Don't handle zero-sized chunks
    if (size == 0)
        return nullptr;

    // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
    // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
    // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
    // policies seem to work well in practice.
    auto size_ptr_it = size_to_free_chunk.lower_bound(size);
    if (size_ptr_it == size_to_free_chunk.end())
        return nullptr;

    // Create the used-chunk, taking its space from the end of the free-chunk
    const size_t size_remaining = size_ptr_it->first - size;
    auto allocated = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
    chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
    if (size_ptr_it->first == size) {
        // whole chunk is used up
        chunks_free.erase(size_ptr_it->second);
    } else {
        // still some memory left in the chunk
        auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
        chunks_free[size_ptr_it->second] = it_remaining;
        chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
    }
    size_to_free_chunk.erase(size_ptr_it);

    return reinterpret_cast<void*>(allocated->first);
}

void Arena::free(void *ptr)
{
    // Freeing the nullptr pointer is OK.
    if (ptr == nullptr) {
        return;
    }

    // Remove chunk from used map
    auto i = chunks_used.find(static_cast<char*>(ptr));
    if (i == chunks_used.end()) {
        throw std::runtime_error("Arena: invalid or double free");
    }
    std::pair<char*, size_t> freed = *i;
    chunks_used.erase(i);

    // coalesce freed with previous chunk
    auto prev = chunks_free_end.find(freed.first);
    if (prev != chunks_free_end.end()) {
        freed.first -= prev->second->first;
        freed.second += prev->second->first;
        size_to_free_chunk.erase(prev->second);
        chunks_free_end.erase(prev);
    }

    // coalesce freed with chunk after freed
    auto next = chunks_free.find(freed.first + freed.second);
    if (next != chunks_free.end()) {
        freed.second += next->second->first;
        size_to_free_chunk.erase(next->second);
        chunks_free.erase(next);
    }

    // Add/set space with coalesced free chunk
    auto it = size_to_free_chunk.emplace(freed.second, freed.first);
    chunks_free[freed.first] = it;
    chunks_free_end[freed.first + freed.second] = it;
}

Arena::Stats Arena::stats() const
{
    Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
    for (const auto& chunk: chunks_used)
        r.used += chunk.second;
    for (const auto& chunk: chunks_free)
        r.free += chunk.second->first;
    r.total = r.used + r.free;
    return r;
}

#ifdef ARENA_DEBUG
static void printchunk(void* base, size_t sz, bool used) {
    std::cout <<
        "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
        " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
        " 0x" << used << std::endl;
}
void Arena::walk() const
{
    for (const auto& chunk: chunks_used)
        printchunk(chunk.first, chunk.second, true);
    std::cout << std::endl;
    for (const auto& chunk: chunks_free)
        printchunk(chunk.first, chunk.second->first, false);
    std::cout << std::endl;
}
#endif

/*******************************************************************************/
// Implementation: Win32LockedPageAllocator

#ifdef WIN32
/** LockedPageAllocator specialized for Windows.
 */
class Win32LockedPageAllocator: public LockedPageAllocator
{
public:
    Win32LockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

Win32LockedPageAllocator::Win32LockedPageAllocator()
{
    // Determine system page size in bytes
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
}
void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    len = align_up(len, page_size);
    void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (addr) {
        // VirtualLock is used to attempt to keep keying material out of swap. Note
        // that it does not provide this as a guarantee, but, in practice, memory
        // that has been VirtualLock'd almost never gets written to the pagefile
        // except in rare circumstances where memory is extremely low.
        *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
    }
    return addr;
}
void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    VirtualUnlock(const_cast<void*>(addr), len);
}

size_t Win32LockedPageAllocator::GetLimit()
{
    // TODO is there a limit on Windows, how to get it?
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: PosixLockedPageAllocator

#ifndef WIN32
/** LockedPageAllocator specialized for OSes that don't try to be
 * special snowflakes.
 */
class PosixLockedPageAllocator: public LockedPageAllocator
{
public:
    PosixLockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

PosixLockedPageAllocator::PosixLockedPageAllocator()
{
    // Determine system page size in bytes
#if defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else                   // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
}

// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
// MAP_ANON which is deprecated
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    void *addr;
    len = align_up(len, page_size);
    addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        return nullptr;
    }
    if (addr) {
        *lockingSuccess = mlock(addr, len) == 0;
#if defined(MADV_DONTDUMP) // Linux
        madvise(addr, len, MADV_DONTDUMP);
#elif defined(MADV_NOCORE) // FreeBSD
        madvise(addr, len, MADV_NOCORE);
#endif
    }
    return addr;
}
void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    munlock(addr, len);
    munmap(addr, len);
}
size_t PosixLockedPageAllocator::GetLimit()
{
#ifdef RLIMIT_MEMLOCK
    struct rlimit rlim;
    if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
        if (rlim.rlim_cur != RLIM_INFINITY) {
            return rlim.rlim_cur;
        }
    }
#endif
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: LockedPool

LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
    allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
{
}

LockedPool::~LockedPool()
{
}
void* LockedPool::alloc(size_t size)
{
    std::lock_guard<std::mutex> lock(mutex);

    // Don't handle impossible sizes
    if (size == 0 || size > ARENA_SIZE)
        return nullptr;

    // Try allocating from each current arena
    for (auto &arena: arenas) {
        void *addr = arena.alloc(size);
        if (addr) {
            return addr;
        }
    }
    // If that fails, create a new one
    if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
        return arenas.back().alloc(size);
    }
    return nullptr;
}

void LockedPool::free(void *ptr)
{
    std::lock_guard<std::mutex> lock(mutex);
    // TODO we can do better than this linear search by keeping a map of arena
    // extents to arena, and looking up the address.
    for (auto &arena: arenas) {
        if (arena.addressInArena(ptr)) {
            arena.free(ptr);
            return;
        }
    }
    throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
}

LockedPool::Stats LockedPool::stats() const
{
    std::lock_guard<std::mutex> lock(mutex);
    LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
    for (const auto &arena: arenas) {
        Arena::Stats i = arena.stats();
        r.used += i.used;
        r.free += i.free;
        r.total += i.total;
        r.chunks_used += i.chunks_used;
        r.chunks_free += i.chunks_free;
    }
    return r;
}

bool LockedPool::new_arena(size_t size, size_t align)
{
    bool locked;
    // If this is the first arena, handle this specially: Cap the upper size
    // by the process limit. This makes sure that the first arena will at least
    // be locked. An exception to this is if the process limit is 0:
    // in this case no memory can be locked at all so we'll skip past this logic.
    if (arenas.empty()) {
        size_t limit = allocator->GetLimit();
        if (limit > 0) {
            size = std::min(size, limit);
        }
    }
    void *addr = allocator->AllocateLocked(size, &locked);
    if (!addr) {
        return false;
    }
    if (locked) {
        cumulative_bytes_locked += size;
    } else if (lf_cb) { // Call the locking-failed callback if locking failed
        if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
            allocator->FreeLocked(addr, size);
            return false;
        }
    }
    arenas.emplace_back(allocator.get(), addr, size, align);
    return true;
}

LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
    Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
{
}
LockedPool::LockedPageArena::~LockedPageArena()
{
    allocator->FreeLocked(base, size);
}

/*******************************************************************************/
// Implementation: LockedPoolManager
//
LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):
    LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)
{
}

bool LockedPoolManager::LockingFailed()
{
    // TODO: log something but how? without including util.h
    return true;
}

void LockedPoolManager::CreateInstance()
{
    // Using a local static instance guarantees that the object is initialized
    // when it's first needed and also deinitialized after all objects that use
    // it are done with it.  I can think of one unlikely scenario where we may
    // have a static deinitialization order/problem, but the check in
    // LockedPoolManagerBase's destructor helps us detect if that ever happens.
#ifdef WIN32
    std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
#else
    std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
#endif
    static LockedPoolManager instance(std::move(allocator));
    LockedPoolManager::_instance = &instance;
}
<|endoftext|>


<commit_before>
#include "yacas/yacasprivate.h"
#include "yacas/deffile.h"
#include "yacas/lispuserfunc.h"
#include "yacas/standard.h"
#include "yacas/lispio.h"
#include "yacas/platfileio.h"
#include "yacas/lispenvironment.h"
#include "yacas/tokenizer.h"
#include "yacas/stringio.h"

LispDefFile::LispDefFile(const LispDefFile& aOther):
    iFileName(aOther.iFileName),
    iIsLoaded(aOther.iIsLoaded)
{
}

LispDefFile::LispDefFile(LispString* aFileName):
    iFileName(aFileName),
    iIsLoaded(false)
{
}

void LispDefFile::SetLoaded()
{
  iIsLoaded = true;
}

LispDefFile* LispDefFiles::File(LispString * aFileName)
{
  // Create a new entry
  LispDefFile* file = LookUp(aFileName);
  if (!file)
  {
    LispDefFile newfile(aFileName);
    // Add the new entry to the hash table
    SetAssociation(newfile, aFileName);
    file = LookUp(aFileName);
  }
  return file;
}

static void DoLoadDefFile(LispEnvironment& aEnvironment, LispInput* aInput,
                          LispDefFile* def)
{
  LispLocalInput localInput(aEnvironment, aInput);

  LispString * eof = aEnvironment.HashTable().LookUp("EndOfFile");
  LispString * end = aEnvironment.HashTable().LookUp("}");
  bool endoffile = false;

  LispTokenizer tok;

  while (!endoffile)
  {
    // Read expression
    LispString * token = tok.NextToken(*aEnvironment.CurrentInput(),
                          aEnvironment.HashTable());

    // Check for end of file
    if (token == eof || token == end)
    {
      endoffile = true;
    }
    // Else evaluate
    else
    {
      LispString * str = token;
      LispMultiUserFunction* multiUser = aEnvironment.MultiUserFunction(str);
      if (multiUser->iFileToOpen!=nullptr)
      {
        aEnvironment.CurrentOutput()->Write("[");
        aEnvironment.CurrentOutput()->Write(&(*str)[0]);
        aEnvironment.CurrentOutput()->Write("]\n");
        if (multiUser->iFileToOpen)
            throw LispErrDefFileAlreadyChosen();
      }
      multiUser->iFileToOpen = def;
    }
  }
}

void LoadDefFile(LispEnvironment& aEnvironment, LispString * aFileName)
{
  assert(aFileName!=nullptr);

  LispString flatfile;
  InternalUnstringify(flatfile, aFileName);
  flatfile[flatfile.size()-1]='.';
  flatfile.push_back('d');
  flatfile.push_back('e');
  flatfile.push_back('f');
  flatfile.push_back('\0');

  LispDefFile* def = aEnvironment.DefFiles().File(aFileName);
  LispString * contents = aEnvironment.FindCachedFile(flatfile.c_str());
  LispString * hashedname = aEnvironment.HashTable().LookUp(flatfile.c_str());

  InputStatus oldstatus = aEnvironment.iInputStatus;
  aEnvironment.iInputStatus.SetTo(hashedname->c_str());

  if (contents)
  {
    StringInput newInput(*contents,aEnvironment.iInputStatus);
    DoLoadDefFile(aEnvironment, &newInput,def);
    delete contents;
  }
  else
  {
    LispLocalFile localFP(aEnvironment, hashedname->c_str(),true,
                          aEnvironment.iInputDirectories);
    if (!localFP.stream.is_open())
        throw LispErrFileNotFound();

    CachedStdFileInput newInput(localFP,aEnvironment.iInputStatus);
    DoLoadDefFile(aEnvironment, &newInput,def);
  }
  aEnvironment.iInputStatus.RestoreFrom(oldstatus);
}

<commit_msg>adjustments to correct string semantics<commit_after>
#include "yacas/yacasprivate.h"
#include "yacas/deffile.h"
#include "yacas/lispuserfunc.h"
#include "yacas/standard.h"
#include "yacas/lispio.h"
#include "yacas/platfileio.h"
#include "yacas/lispenvironment.h"
#include "yacas/tokenizer.h"
#include "yacas/stringio.h"

LispDefFile::LispDefFile(const LispDefFile& aOther):
    iFileName(aOther.iFileName),
    iIsLoaded(aOther.iIsLoaded)
{
}

LispDefFile::LispDefFile(LispString* aFileName):
    iFileName(aFileName),
    iIsLoaded(false)
{
}

void LispDefFile::SetLoaded()
{
  iIsLoaded = true;
}

LispDefFile* LispDefFiles::File(LispString * aFileName)
{
  // Create a new entry
  LispDefFile* file = LookUp(aFileName);
  if (!file)
  {
    LispDefFile newfile(aFileName);
    // Add the new entry to the hash table
    SetAssociation(newfile, aFileName);
    file = LookUp(aFileName);
  }
  return file;
}

static void DoLoadDefFile(LispEnvironment& aEnvironment, LispInput* aInput,
                          LispDefFile* def)
{
  LispLocalInput localInput(aEnvironment, aInput);

  LispString * eof = aEnvironment.HashTable().LookUp("EndOfFile");
  LispString * end = aEnvironment.HashTable().LookUp("}");
  bool endoffile = false;

  LispTokenizer tok;

  while (!endoffile)
  {
    // Read expression
    LispString * token = tok.NextToken(*aEnvironment.CurrentInput(),
                          aEnvironment.HashTable());

    // Check for end of file
    if (token == eof || token == end)
    {
      endoffile = true;
    }
    // Else evaluate
    else
    {
      LispString * str = token;
      LispMultiUserFunction* multiUser = aEnvironment.MultiUserFunction(str);
      if (multiUser->iFileToOpen!=nullptr)
      {
        aEnvironment.CurrentOutput()->Write("[");
        aEnvironment.CurrentOutput()->Write(&(*str)[0]);
        aEnvironment.CurrentOutput()->Write("]\n");
        if (multiUser->iFileToOpen)
            throw LispErrDefFileAlreadyChosen();
      }
      multiUser->iFileToOpen = def;
    }
  }
}

void LoadDefFile(LispEnvironment& aEnvironment, LispString * aFileName)
{
  assert(aFileName!=nullptr);

  LispString flatfile;
  InternalUnstringify(flatfile, aFileName);
  flatfile.append(".def");
  LispDefFile* def = aEnvironment.DefFiles().File(aFileName);
  LispString * contents = aEnvironment.FindCachedFile(flatfile.c_str());
  LispString * hashedname = aEnvironment.HashTable().LookUp(flatfile.c_str());

  InputStatus oldstatus = aEnvironment.iInputStatus;
  aEnvironment.iInputStatus.SetTo(hashedname->c_str());

  if (contents)
  {
    StringInput newInput(*contents,aEnvironment.iInputStatus);
    DoLoadDefFile(aEnvironment, &newInput,def);
    delete contents;
  }
  else
  {
    LispLocalFile localFP(aEnvironment, hashedname->c_str(),true,
                          aEnvironment.iInputDirectories);
    if (!localFP.stream.is_open())
        throw LispErrFileNotFound();

    CachedStdFileInput newInput(localFP,aEnvironment.iInputStatus);
    DoLoadDefFile(aEnvironment, &newInput,def);
  }
  aEnvironment.iInputStatus.RestoreFrom(oldstatus);
}

<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////
/*
 *  Amira Reader for the nrrd (Nearly Raw Raster Data) format:
 *  http://teem.sourceforge.net/nrrd/format.html
 *  Currently only supports 3d single channel data
 *  Copyright 2009 Gregory Jefferis. All rights reserved.
 *  License GPL >=3
 *  Certain portions of this code were copied/amended from the CMTK
 *  library: http://www.nitrc.org/projects/cmtk/
 */
/////////////////////////////////////////////////////////////////
#include <NrrdIO/NrrdIOAPI.h>

#include <hxfield/HxUniformScalarField3.h>
#include <Amira/HxMessage.h>
#include <teem/nrrd.h>

NRRDIO_API
int NrrdReader(const char* filename)
{

	Nrrd *nrrd = nrrdNew();
	if ( nrrdLoad( nrrd, filename, NULL ) )
		throw biffGetDone(NRRD);

    if ( nrrd->dim > 4 )
	{
		theMsg->printf("ERROR: for now, nrrd input can only handle data with dimension 4 or less.");
		return 0;
	} else if ( nrrd->spaceDim > 3 ){
		theMsg->printf("ERROR: for now, nrrd input can only handle data with space dimension 3 or less.");
		return 0;
	}

    const int dims[4] =
	{
		(nrrd->dim > 0) ? nrrd->axis[0].size : 1,
		(nrrd->dim > 1) ? nrrd->axis[1].size : 1,
		(nrrd->dim > 2) ? nrrd->axis[2].size : 1,
		(nrrd->dim > 3) ? nrrd->axis[3].size : 1
	};

	McPrimType pType = NULL;
	switch ( nrrd->type )
	{
		case nrrdTypeUChar:  pType = MC_UINT8; break;
		case nrrdTypeChar:   pType = MC_INT8;  break;
		case nrrdTypeUShort: pType = MC_UINT16;break;
		case nrrdTypeShort:  pType = MC_INT16; break;
		case nrrdTypeInt:    pType = MC_INT32; break;
		case nrrdTypeFloat:  pType = MC_FLOAT; break;
		case nrrdTypeDouble: pType = MC_DOUBLE;break;
		default: break;
	}

	if(pType == NULL)
	{
		theMsg->printf("ERROR: unknown nrrd input type.");
		return 0;
	}

	// First fetch axis spacing
	double spacing[3] = { 1.0, 1.0, 1.0 };
	int firstSpaceAxis = -1;
	int numSpaceAxesSoFar = 0;
	int nonSpatialDimension = -1;
	for ( unsigned int ax = 0; ax < nrrd->dim; ++ax )
	{
		switch ( nrrd->axis[ax].kind )
		{
			case nrrdKindUnknown:
			case nrrdKindDomain:
			case nrrdKindSpace:
			case nrrdKindTime: firstSpaceAxis=firstSpaceAxis<0?ax:firstSpaceAxis; break;
			default: nonSpatialDimension = ax; continue;
		}
		switch ( nrrdSpacingCalculate( nrrd, ax, spacing+numSpaceAxesSoFar, nrrd->axis[ax].spaceDirection ) )
		{
			case nrrdSpacingStatusScalarNoSpace:
				break;
			case nrrdSpacingStatusDirection:
				break;
			case nrrdSpacingStatusScalarWithSpace:
				theMsg->printf("WARNING: nrrdSpacingCalculate returned nrrdSpacingStatusScalarWithSpace\n");
				spacing[numSpaceAxesSoFar] = nrrd->axis[ax].spacing;
				break;
			case nrrdSpacingStatusNone:
			default:
				theMsg->printf("WARNING: no pixel spacings in Nrrd for axis %d ; setting to 1.0\n",ax);
				spacing[numSpaceAxesSoFar] = 1.0;
				break;
		}
		numSpaceAxesSoFar++;
	}
	if ( firstSpaceAxis < 0 || firstSpaceAxis >1 )
	{
		theMsg->printf("ERROR: Unable to identify first spatial axis in nrrd. Got %d\n", firstSpaceAxis);
		return 0;
	}

	// Figure out size of non-spatial dimension (ie vector, colour etc)
	int nDataVar = 1;
	if ( nonSpatialDimension == 0) nDataVar = dims[nonSpatialDimension];
	else if ( nonSpatialDimension > 0) {
		// At the moment we can't handle having the vector dimension come later because
		// that would require shuffling the nrrd data block to prepare it for Amira
		theMsg->printf("ERROR: Only nrrds with vector values in the 0th dimension (not %d) are currently supported\n", nonSpatialDimension);
		return 0;
	}

	// Initialise coordinates (these will be uniform) starting at first space axis
	HxUniformCoord3* coord = new HxUniformCoord3(&dims[firstSpaceAxis]);

	// Now let's set the physical dimensions
	// This is done by defining the bounding box, the range of the voxel centres
	// given in the order: xmin,xmax,ymin ...
	float *bbox = coord->bbox();
	bbox[0] = isnan(nrrd->spaceOrigin[0])?0.0f:(float) nrrd->spaceOrigin[0];
	bbox[2] = isnan(nrrd->spaceOrigin[1])?0.0f:(float) nrrd->spaceOrigin[1];
	bbox[4] = isnan(nrrd->spaceOrigin[2])?0.0f:(float) nrrd->spaceOrigin[2];

	// When a dimension is 1, Amira still seems to have a defined spacing
	bbox[1] = bbox[0] + (float) spacing[0] * ( dims[0+firstSpaceAxis] == 1 ? 1 : (dims[0+firstSpaceAxis] - 1) );
	bbox[3] = bbox[2] + (float) spacing[1] * ( dims[1+firstSpaceAxis] == 1 ? 1 : (dims[1+firstSpaceAxis] - 1) );
	bbox[5] = bbox[4] + (float) spacing[2] * ( dims[2+firstSpaceAxis] == 1 ? 1 : (dims[2+firstSpaceAxis] - 1) );

	// Finally initialise lattice
	HxLattice3* lattice = new HxLattice3(nDataVar, pType, coord, nrrd->data);
	HxField3* field = HxLattice3::create(lattice);

	// Shouldn't need to check for data loading
	HxData::registerData(field, filename);

    return 1;
}

<commit_msg>Fix a problem handling data types<commit_after>/////////////////////////////////////////////////////////////////
/*
 *  Amira Reader for the nrrd (Nearly Raw Raster Data) format:
 *  http://teem.sourceforge.net/nrrd/format.html
 *  Currently only supports 3d single channel data
 *  Copyright 2009 Gregory Jefferis. All rights reserved.
 *  License GPL >=3
 *  Certain portions of this code were copied/amended from the CMTK
 *  library: http://www.nitrc.org/projects/cmtk/
 */
/////////////////////////////////////////////////////////////////
#include <NrrdIO/NrrdIOAPI.h>

#include <hxfield/HxUniformScalarField3.h>
#include <Amira/HxMessage.h>
#include <teem/nrrd.h>

NRRDIO_API
int NrrdReader(const char* filename)
{

	Nrrd *nrrd = nrrdNew();
	if ( nrrdLoad( nrrd, filename, NULL ) )
		throw biffGetDone(NRRD);

    if ( nrrd->dim > 4 )
	{
		theMsg->printf("ERROR: for now, nrrd input can only handle data with dimension 4 or less.");
		return 0;
	} else if ( nrrd->spaceDim > 3 ){
		theMsg->printf("ERROR: for now, nrrd input can only handle data with space dimension 3 or less.");
		return 0;
	}

    const int dims[4] =
	{
		(nrrd->dim > 0) ? nrrd->axis[0].size : 1,
		(nrrd->dim > 1) ? nrrd->axis[1].size : 1,
		(nrrd->dim > 2) ? nrrd->axis[2].size : 1,
		(nrrd->dim > 3) ? nrrd->axis[3].size : 1
	};

	theMsg->printf("nrrd type is: %d\n",nrrd->type);

	int pType = -1;
	switch ( nrrd->type )
	{
		case nrrdTypeUChar:  pType = McPrimType::mc_uint8; break;
		case nrrdTypeChar:   pType = McPrimType::mc_int8;  break;
		case nrrdTypeUShort: pType = McPrimType::mc_uint16;break;
		case nrrdTypeShort:  pType = McPrimType::mc_int16; break;
		case nrrdTypeInt:    pType = McPrimType::mc_int32; break;
		case nrrdTypeFloat:  pType = McPrimType::mc_float; break;
		case nrrdTypeDouble: pType = McPrimType::mc_double;break;
		default: break;
	}

	if(pType < 0)
	{
		theMsg->printf("ERROR: unknown nrrd input type.");
		return 0;
	}

	// First fetch axis spacing
	double spacing[3] = { 1.0, 1.0, 1.0 };
	int firstSpaceAxis = -1;
	int numSpaceAxesSoFar = 0;
	int nonSpatialDimension = -1;
	for ( unsigned int ax = 0; ax < nrrd->dim; ++ax )
	{
		switch ( nrrd->axis[ax].kind )
		{
			case nrrdKindUnknown:
			case nrrdKindDomain:
			case nrrdKindSpace:
			case nrrdKindTime: firstSpaceAxis=firstSpaceAxis<0?ax:firstSpaceAxis; break;
			default: nonSpatialDimension = ax; continue;
		}
		switch ( nrrdSpacingCalculate( nrrd, ax, spacing+numSpaceAxesSoFar, nrrd->axis[ax].spaceDirection ) )
		{
			case nrrdSpacingStatusScalarNoSpace:
				break;
			case nrrdSpacingStatusDirection:
				break;
			case nrrdSpacingStatusScalarWithSpace:
				theMsg->printf("WARNING: nrrdSpacingCalculate returned nrrdSpacingStatusScalarWithSpace\n");
				spacing[numSpaceAxesSoFar] = nrrd->axis[ax].spacing;
				break;
			case nrrdSpacingStatusNone:
			default:
				theMsg->printf("WARNING: no pixel spacings in Nrrd for axis %d ; setting to 1.0\n",ax);
				spacing[numSpaceAxesSoFar] = 1.0;
				break;
		}
		numSpaceAxesSoFar++;
	}
	if ( firstSpaceAxis < 0 || firstSpaceAxis >1 )
	{
		theMsg->printf("ERROR: Unable to identify first spatial axis in nrrd. Got %d\n", firstSpaceAxis);
		return 0;
	}

	// Figure out size of non-spatial dimension (ie vector, colour etc)
	int nDataVar = 1;
	if ( nonSpatialDimension == 0) nDataVar = dims[nonSpatialDimension];
	else if ( nonSpatialDimension > 0) {
		// At the moment we can't handle having the vector dimension come later because
		// that would require shuffling the nrrd data block to prepare it for Amira
		theMsg->printf("ERROR: Only nrrds with vector values in the 0th dimension (not %d) are currently supported\n", nonSpatialDimension);
		return 0;
	}

	// Initialise coordinates (these will be uniform) starting at first space axis
	HxUniformCoord3* coord = new HxUniformCoord3(&dims[firstSpaceAxis]);

	// Now let's set the physical dimensions
	// This is done by defining the bounding box, the range of the voxel centres
	// given in the order: xmin,xmax,ymin ...
	float *bbox = coord->bbox();
	bbox[0] = isnan(nrrd->spaceOrigin[0])?0.0f:(float) nrrd->spaceOrigin[0];
	bbox[2] = isnan(nrrd->spaceOrigin[1])?0.0f:(float) nrrd->spaceOrigin[1];
	bbox[4] = isnan(nrrd->spaceOrigin[2])?0.0f:(float) nrrd->spaceOrigin[2];

	// When a dimension is 1, Amira still seems to have a defined spacing
	bbox[1] = bbox[0] + (float) spacing[0] * ( dims[0+firstSpaceAxis] == 1 ? 1 : (dims[0+firstSpaceAxis] - 1) );
	bbox[3] = bbox[2] + (float) spacing[1] * ( dims[1+firstSpaceAxis] == 1 ? 1 : (dims[1+firstSpaceAxis] - 1) );
	bbox[5] = bbox[4] + (float) spacing[2] * ( dims[2+firstSpaceAxis] == 1 ? 1 : (dims[2+firstSpaceAxis] - 1) );

	// Finally initialise lattice
	HxLattice3* lattice = new HxLattice3(nDataVar, pType, coord, nrrd->data);
	HxField3* field = HxLattice3::create(lattice);

	// Shouldn't need to check for data loading
	HxData::registerData(field, filename);

    return 1;
}

<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////
/*
 *  Amira Reader for the nrrd (Nearly Raw Raster Data) format:
 *  http://teem.sourceforge.net/nrrd/format.html
 *  Currently only supports 3d single channel data
 *  Copyright 2009 Gregory Jefferis. All rights reserved.
 *  License GPL >=3
 *  Certain portions of this code were copied/amended from the CMTK
 *  library: http://www.nitrc.org/projects/cmtk/
 */
/////////////////////////////////////////////////////////////////
#include <NrrdIO/NrrdIOAPI.h>

#include <hxfield/HxUniformScalarField3.h>
#include <Amira/HxMessage.h>
#include <teem/nrrd.h>

NRRDIO_API
int NrrdReader(const char* filename)
{

	Nrrd *nrrd = nrrdNew();
	if ( nrrdLoad( nrrd, filename, NULL ) )
		throw biffGetDone(NRRD);

    if ( nrrd->dim > 3 )
	{
		theMsg->printf("ERROR: for now, nrrd input can only handle data with dimension 3 or less.");
		return 0;
	}

    const int dims[3] =
	{
		(nrrd->dim > 0) ? nrrd->axis[0].size : 1,
		(nrrd->dim > 1) ? nrrd->axis[1].size : 1,
		(nrrd->dim > 2) ? nrrd->axis[2].size : 1
	};

	HxUniformScalarField3* field = NULL;

	switch ( nrrd->type )
	{
		case nrrdTypeUChar:  field = new HxUniformScalarField3(dims,MC_UINT8,nrrd->data); break;
		case nrrdTypeChar:   field = new HxUniformScalarField3(dims,MC_INT8,nrrd->data); break;
		case nrrdTypeUShort: field = new HxUniformScalarField3(dims,MC_UINT16,nrrd->data); break;
		case nrrdTypeShort:  field = new HxUniformScalarField3(dims,MC_INT16,nrrd->data); break;
		case nrrdTypeInt:    field = new HxUniformScalarField3(dims,MC_INT32,nrrd->data); break;
		case nrrdTypeFloat:  field = new HxUniformScalarField3(dims,MC_FLOAT,nrrd->data); break;
		case nrrdTypeDouble: field = new HxUniformScalarField3(dims,MC_DOUBLE,nrrd->data); break;
		default: break;
	}

	if(field == NULL)
	{
		theMsg->printf("ERROR: unknown nrrd input type.");
		return 0;
	}

	// First fetch axis spacing
	double spacing[3] = { 1.0, 1.0, 1.0 };
	for ( size_t ax = 0; ax < nrrd->dim; ++ax )
	{
		switch ( nrrdSpacingCalculate( nrrd, ax, spacing+ax, nrrd->axis[ax].spaceDirection ) )
		{
			case nrrdSpacingStatusScalarNoSpace:
				break;
			case nrrdSpacingStatusDirection:
				break;
			case nrrdSpacingStatusScalarWithSpace:
				theMsg->printf("WARNING: nrrdSpacingCalculate returned nrrdSpacingStatusScalarWithSpace\n");
				spacing[ax] = nrrd->axis[ax].spacing;
				break;
			case nrrdSpacingStatusNone:
			default:
				theMsg->printf("WARNING: no pixel spacings in Nrrd for axis %d ; setting to 1.0\n",ax);
				spacing[ax] = 1.0;
				break;
		}
	}

	// Now let's set the physical dimensions
	// This is done by defining the bounding box, the range of the voxel centres
	// given in the order: xmin,xmax,ymin ...
	float *bbox = field->bbox();
	bbox[0] = isnan(nrrd->spaceOrigin[0])?0.0f:(float) nrrd->spaceOrigin[0];
	bbox[2] = isnan(nrrd->spaceOrigin[1])?0.0f:(float) nrrd->spaceOrigin[1];
	bbox[4] = isnan(nrrd->spaceOrigin[2])?0.0f:(float) nrrd->spaceOrigin[2];

	// When a dimension is 1, Amira still seems to have a defined spacing
	bbox[1] = bbox[0] + (float) spacing[0] * ( dims[0] == 1 ? 1 : (dims[0] - 1) );
	bbox[3] = bbox[2] + (float) spacing[1] * ( dims[1] == 1 ? 1 : (dims[1] - 1) );
	bbox[5] = bbox[4] + (float) spacing[2] * ( dims[2] == 1 ? 1 : (dims[2] - 1) );

	// Shouldn't need to check for data loading
	HxData::registerData(field, filename);

    return 1;
}

<commit_msg>Separate identification of primitive type from making field object<commit_after>/////////////////////////////////////////////////////////////////
/*
 *  Amira Reader for the nrrd (Nearly Raw Raster Data) format:
 *  http://teem.sourceforge.net/nrrd/format.html
 *  Currently only supports 3d single channel data
 *  Copyright 2009 Gregory Jefferis. All rights reserved.
 *  License GPL >=3
 *  Certain portions of this code were copied/amended from the CMTK
 *  library: http://www.nitrc.org/projects/cmtk/
 */
/////////////////////////////////////////////////////////////////
#include <NrrdIO/NrrdIOAPI.h>

#include <hxfield/HxUniformScalarField3.h>
#include <Amira/HxMessage.h>
#include <teem/nrrd.h>

NRRDIO_API
int NrrdReader(const char* filename)
{

	Nrrd *nrrd = nrrdNew();
	if ( nrrdLoad( nrrd, filename, NULL ) )
		throw biffGetDone(NRRD);

    if ( nrrd->dim > 3 )
	{
		theMsg->printf("ERROR: for now, nrrd input can only handle data with dimension 3 or less.");
		return 0;
	}

    const int dims[3] =
	{
		(nrrd->dim > 0) ? nrrd->axis[0].size : 1,
		(nrrd->dim > 1) ? nrrd->axis[1].size : 1,
		(nrrd->dim > 2) ? nrrd->axis[2].size : 1
	};

	McPrimType pType = NULL;
	switch ( nrrd->type )
	{
		case nrrdTypeUChar:  pType = MC_UINT8; break;
		case nrrdTypeChar:   pType = MC_INT8;  break;
		case nrrdTypeUShort: pType = MC_UINT16;break;
		case nrrdTypeShort:  pType = MC_INT16; break;
		case nrrdTypeInt:    pType = MC_INT32; break;
		case nrrdTypeFloat:  pType = MC_FLOAT; break;
		case nrrdTypeDouble: pType = MC_DOUBLE;break;
		default: break;
	}

	if(pType == NULL)
	{
		theMsg->printf("ERROR: unknown nrrd input type.");
		return 0;
	}

	HxUniformScalarField3* field = new HxUniformScalarField3(dims,pType,nrrd->data);

	// First fetch axis spacing
	double spacing[3] = { 1.0, 1.0, 1.0 };
	for ( size_t ax = 0; ax < nrrd->dim; ++ax )
	{
		switch ( nrrdSpacingCalculate( nrrd, ax, spacing+ax, nrrd->axis[ax].spaceDirection ) )
		{
			case nrrdSpacingStatusScalarNoSpace:
				break;
			case nrrdSpacingStatusDirection:
				break;
			case nrrdSpacingStatusScalarWithSpace:
				theMsg->printf("WARNING: nrrdSpacingCalculate returned nrrdSpacingStatusScalarWithSpace\n");
				spacing[ax] = nrrd->axis[ax].spacing;
				break;
			case nrrdSpacingStatusNone:
			default:
				theMsg->printf("WARNING: no pixel spacings in Nrrd for axis %d ; setting to 1.0\n",ax);
				spacing[ax] = 1.0;
				break;
		}
	}

	// Now let's set the physical dimensions
	// This is done by defining the bounding box, the range of the voxel centres
	// given in the order: xmin,xmax,ymin ...
	float *bbox = field->bbox();
	bbox[0] = isnan(nrrd->spaceOrigin[0])?0.0f:(float) nrrd->spaceOrigin[0];
	bbox[2] = isnan(nrrd->spaceOrigin[1])?0.0f:(float) nrrd->spaceOrigin[1];
	bbox[4] = isnan(nrrd->spaceOrigin[2])?0.0f:(float) nrrd->spaceOrigin[2];

	// When a dimension is 1, Amira still seems to have a defined spacing
	bbox[1] = bbox[0] + (float) spacing[0] * ( dims[0] == 1 ? 1 : (dims[0] - 1) );
	bbox[3] = bbox[2] + (float) spacing[1] * ( dims[1] == 1 ? 1 : (dims[1] - 1) );
	bbox[5] = bbox[4] + (float) spacing[2] * ( dims[2] == 1 ? 1 : (dims[2] - 1) );

	// Shouldn't need to check for data loading
	HxData::registerData(field, filename);

    return 1;
}

<|endoftext|>


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

#include "phd.h"
#include "about_dialog.h"
#include <wx/fs_mem.h>
#include <wx/html/htmlwin.h>

BEGIN_EVENT_TABLE(AboutDialog, wxDialog)
    EVT_HTML_LINK_CLICKED(ABOUT_LINK,AboutDialog::OnLink)
END_EVENT_TABLE()

AboutDialog::AboutDialog(void) :
wxDialog(pFrame, wxID_ANY, _T("About ") APPNAME, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
{
    SetBackgroundColour(*wxWHITE);

    wxBoxSizer *pSizer = new wxBoxSizer(wxHORIZONTAL);

    #include "icons/phd2_64.png.h"
    wxBitmap phd2(wxBITMAP_PNG_FROM_DATA(phd2_64));
    wxStaticBitmap *pImage = new wxStaticBitmap(this, wxID_ANY, phd2);

    wxFileSystem::AddHandler(new wxMemoryFSHandler);
    wxMemoryFSHandler::AddFile("about.html", wxString::Format(
        ""
        "
%s %s
"
        "PHD2 home page - openphdguiding.org
"
        "PHD2 open source project page

"
        ""
        "Credits:
"
        "
"
        "
"
        "Craig Stark	"
        "Bret McKee	"
        "
"
        "
"
        "Andy Galasso	"
        "Bernhard Reutner-Fischer	"
        "
"
        "
"
        "Stefan Elste	"
        "Geoffrey Hausheer	"
        "
"
        "
"
        "Jared Wellman	"
        "John Wainwright	"
        "
"
        "
"
        "Sylvain Girard	"
        "Bruce Waddington	"
        "
"
        "
"
        "Max Chen	"
        "Carsten Przygoda	"
        "
"
        "
"
        "Hans Lambermont	"
        "David Ault	"
        "
"
        "
"
        "Markus Wieczorek	"
        "Linkage	"
        "
"
        "
"
        "Robin Glover	"
        "Patrick Chevalley	"
        "
"
        "
"
        "Scott Edwards	"
        "Eiji Kaneshige	"
        "
"
        "
"
        "Konstantin Menshikoff   	"
        "Jakub Bartas	"
        "
"
        "
"
        "Javier R	"
        "Oleh Malyi	"
        "
"
        "
"
        "Tsung-Chi Wu	"
        "Raffi Enficiaud	"
        "
"
        "
"
        "Sabin Fota	"
        "Dylan O'Donnell	"
        "
"
        "
"
        "Katsuhiro Kojima	"
        "Simon Taylor	"
        "
"
        "
"
        "Hallgeir Holien	"
        "Laurent Schmitz	"
        "
"
        "
"
        "Atushi Sakauchi	"
        "Giorgio Mazzacurati	"
        "
"
        "
"
        "G\u00FCnter Scholz	"
        "Ray Gralak	"
        "
"
        "
"
        "Khalefa Algadi	"
        "David C. Partridge	"
        "
"
        "
"
        "Matteo Ghellere	"
        "norma	"
        "
"
        "Edgar D. Klenske	"
        "Bernhard Schölkopf	"
        "
"
        "
"
        "Philipp Hennig	"
        "Stephan Wenninger	"
        "
"
        "
"
        "Wagner Trindade	"
        "Cyril Richard	"
        "
"
        "
"
        "Mattia Verga	"
        "Iv\u00E1n Zabala	"
        "
"
        "
"
        "Ken Self	"
        "	"
        "
"
        "

"
        "
"
        "
"
        "Copyright 2006-2013 Craig Stark
"
        "Copyright 2009 Geoffrey Hausheer
"
        "Copyright 2012-2013 Bret McKee
"
        "Copyright 2013 Sylvain Girard
"
        "Copyright 2013-2018 Andy Galasso
"
        "Copyright 2013-2018 Bruce Waddington
"
        "Copyright 2014 Hans Lambermont
"
        "Copyright 2014 Robin Glover
"
        "Copyright 2014-2017 Max Planck Society
"
        "Copyright 2017 Ken Self
"
        "
"
        "
"
        "The Predictive PEC guide algorithm is based on
"
        "Gaussian Process Based Predictive Control
for Periodic Error Correction"
        ""
        "", APPNAME, FULLVER));
    wxHtmlWindow *pHtml;
    pHtml = new wxHtmlWindow(this, ABOUT_LINK, wxDefaultPosition, wxSize(380, 540), wxHW_SCROLLBAR_AUTO);
    pHtml->SetBorders(0);
    pHtml->LoadPage("memory:about.html");
    pHtml->SetSize(pHtml->GetInternalRepresentation()->GetWidth(), pHtml->GetInternalRepresentation()->GetHeight());

    pSizer->Add(pImage, wxSizerFlags(0).Border(wxALL, 10));
    pSizer->Add(pHtml, wxSizerFlags(0).Border(wxALL, 10));

    wxBoxSizer *pTopLevelSizer = new wxBoxSizer(wxVERTICAL);
    pTopLevelSizer->Add(pSizer, wxSizerFlags(0).Expand());
    pTopLevelSizer->Add(CreateButtonSizer(wxOK), wxSizerFlags(0).Expand().Border(wxALL, 10));
    SetSizerAndFit(pTopLevelSizer);
}

AboutDialog::~AboutDialog(void)
{
    wxMemoryFSHandler::RemoveFile("about.html");
}

void AboutDialog::OnLink(wxHtmlLinkEvent & event)
{
    wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref());
}
<commit_msg>add Alex Helms to list of contributors<commit_after>/*
 *  about_dialog.cpp
 *  PHD Guiding
 *
 *  Created by Sylvain Girard.
 *  Copyright (c) 2013 Sylvain Girard.
 *  All rights reserved.
 *
 *  This source code is distributed under the following "BSD" license
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *    Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *    Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *    Neither the name of Craig Stark, Stark Labs nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "phd.h"
#include "about_dialog.h"
#include <wx/fs_mem.h>
#include <wx/html/htmlwin.h>

BEGIN_EVENT_TABLE(AboutDialog, wxDialog)
    EVT_HTML_LINK_CLICKED(ABOUT_LINK,AboutDialog::OnLink)
END_EVENT_TABLE()

AboutDialog::AboutDialog(void) :
wxDialog(pFrame, wxID_ANY, _T("About ") APPNAME, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
{
    SetBackgroundColour(*wxWHITE);

    wxBoxSizer *pSizer = new wxBoxSizer(wxHORIZONTAL);

    #include "icons/phd2_64.png.h"
    wxBitmap phd2(wxBITMAP_PNG_FROM_DATA(phd2_64));
    wxStaticBitmap *pImage = new wxStaticBitmap(this, wxID_ANY, phd2);

    wxFileSystem::AddHandler(new wxMemoryFSHandler);
    wxMemoryFSHandler::AddFile("about.html", wxString::Format(
        ""
        "
%s %s
"
        "PHD2 home page - openphdguiding.org
"
        "PHD2 open source project page

"
        ""
        "Credits:
"
        "
"
        "
"
        "Craig Stark	"
        "Bret McKee	"
        "
"
        "
"
        "Andy Galasso	"
        "Bernhard Reutner-Fischer	"
        "
"
        "
"
        "Stefan Elste	"
        "Geoffrey Hausheer	"
        "
"
        "
"
        "Jared Wellman	"
        "John Wainwright	"
        "
"
        "
"
        "Sylvain Girard	"
        "Bruce Waddington	"
        "
"
        "
"
        "Max Chen	"
        "Carsten Przygoda	"
        "
"
        "
"
        "Hans Lambermont	"
        "David Ault	"
        "
"
        "
"
        "Markus Wieczorek	"
        "Linkage	"
        "
"
        "
"
        "Robin Glover	"
        "Patrick Chevalley	"
        "
"
        "
"
        "Scott Edwards	"
        "Eiji Kaneshige	"
        "
"
        "
"
        "Konstantin Menshikoff   	"
        "Jakub Bartas	"
        "
"
        "
"
        "Javier R	"
        "Oleh Malyi	"
        "
"
        "
"
        "Tsung-Chi Wu	"
        "Raffi Enficiaud	"
        "
"
        "
"
        "Sabin Fota	"
        "Dylan O'Donnell	"
        "
"
        "
"
        "Katsuhiro Kojima	"
        "Simon Taylor	"
        "
"
        "
"
        "Hallgeir Holien	"
        "Laurent Schmitz	"
        "
"
        "
"
        "Atushi Sakauchi	"
        "Giorgio Mazzacurati	"
        "
"
        "
"
        "G\u00FCnter Scholz	"
        "Ray Gralak	"
        "
"
        "
"
        "Khalefa Algadi	"
        "David C. Partridge	"
        "
"
        "
"
        "Matteo Ghellere	"
        "norma	"
        "
"
        "Edgar D. Klenske	"
        "Bernhard Schölkopf	"
        "
"
        "
"
        "Philipp Hennig	"
        "Stephan Wenninger	"
        "
"
        "
"
        "Wagner Trindade	"
        "Cyril Richard	"
        "
"
        "
"
        "Mattia Verga	"
        "Iv\u00E1n Zabala	"
        "
"
        "
"
        "Ken Self	"
        "Alex Helms	"
        "
"
        "

"
        "
"
        "
"
        "Copyright 2006-2013 Craig Stark
"
        "Copyright 2009 Geoffrey Hausheer
"
        "Copyright 2012-2013 Bret McKee
"
        "Copyright 2013 Sylvain Girard
"
        "Copyright 2013-2018 Andy Galasso
"
        "Copyright 2013-2018 Bruce Waddington
"
        "Copyright 2014 Hans Lambermont
"
        "Copyright 2014 Robin Glover
"
        "Copyright 2014-2017 Max Planck Society
"
        "Copyright 2017 Ken Self
"
        "
"
        "
"
        "The Predictive PEC guide algorithm is based on
"
        "Gaussian Process Based Predictive Control
for Periodic Error Correction"
        ""
        "", APPNAME, FULLVER));
    wxHtmlWindow *pHtml;
    pHtml = new wxHtmlWindow(this, ABOUT_LINK, wxDefaultPosition, wxSize(380, 540), wxHW_SCROLLBAR_AUTO);
    pHtml->SetBorders(0);
    pHtml->LoadPage("memory:about.html");
    pHtml->SetSize(pHtml->GetInternalRepresentation()->GetWidth(), pHtml->GetInternalRepresentation()->GetHeight());

    pSizer->Add(pImage, wxSizerFlags(0).Border(wxALL, 10));
    pSizer->Add(pHtml, wxSizerFlags(0).Border(wxALL, 10));

    wxBoxSizer *pTopLevelSizer = new wxBoxSizer(wxVERTICAL);
    pTopLevelSizer->Add(pSizer, wxSizerFlags(0).Expand());
    pTopLevelSizer->Add(CreateButtonSizer(wxOK), wxSizerFlags(0).Expand().Border(wxALL, 10));
    SetSizerAndFit(pTopLevelSizer);
}

AboutDialog::~AboutDialog(void)
{
    wxMemoryFSHandler::RemoveFile("about.html");
}

void AboutDialog::OnLink(wxHtmlLinkEvent & event)
{
    wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref());
}
<|endoftext|>


<commit_before><commit_msg>coverity#440978 Dereference before null check<commit_after><|endoftext|>


<commit_before>#include "sysexmessage.h"
#include "ack.h"

#include <algorithm>
#include <iostream>
#include <unistd.h>

/*
 * Structure and naming od sysex data
 *
 * SYSEX_START 1Byte
 * MANUFACTURER_CODE 3Byte--| Header
 * MESSAGE_CLASS 1Byte ------
 *
 * PRODUCT_ID 2Byte --------| DeviceId -
 * SERIAL_NUMBER 5 Byte -----          |
 *                                     |
 * TRANSACTION_ID 2Byte ----|          | Body (Relevant for Checksum)
 * COMMAND 2Byte            |          |
 * DATA_LENGTH 2Byte        |          |
 * COMMAND_DATA xByte -------          |
 *                          -----------|
 * X_SUM 1yte
 *
 * SYSEX_END 1Byte
 *
 * ST| Man.Id |MC| PID | Serial No.   | TID | CID | LEN  | Data|CS|SE
 * 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17   ...  .. ..
 * F0 00 01 73 7E xx xx xx xx xx xx xx xx xx xx xx xx xx  xxxx  xx F7
 */

SysExMessage::SysExMessage(Command cmd, CommandFlags flags, Device *device)
    : cmd(cmd), cmdflags(flags), device(device) {
  if (this->device != 0)
    this->deviceHeader = this->device->getDeviceHeader();
  else
    deviceHeader = new BYTE_VECTOR();
  command = new BYTE_VECTOR();
  command->push_back(flags);
  command->push_back(cmd);
  acceptedAnswers = commandAcceptedAnswers[cmd];
}

SysExMessage::SysExMessage(Command cmd, std::vector<unsigned char> *message,
                           Device *device)
    : cmd(cmd), device(device) {
  if (this->device != 0)
    this->deviceHeader = this->device->getDeviceHeader();
  else
    deviceHeader = new BYTE_VECTOR();
  cmdflags = (*message)[14];
  command = new BYTE_VECTOR();
  command->push_back(cmdflags);
  command->push_back(cmd);
  acceptedAnswers = commandAcceptedAnswers[cmd];
  extractData(message);
}

SysExMessage::~SysExMessage() {
  delete command;
  delete deviceHeader;
}

void SysExMessage::extractData(std::vector<unsigned char> *message) {
  long dataLength = MIDI::byteJoin(
      new BYTE_VECTOR(message->begin() + Device::DATA_LENGTH_OFFSET,
                      message->begin() + Device::DATA_LENGTH_OFFSET +
                          Device::DATA_LENGTH_LENGTH));
  data = new BYTE_VECTOR(message->begin() + Device::DATA_OFFSET,
                         message->begin() + Device::DATA_OFFSET + dataLength);
}

BYTE_VECTOR *SysExMessage::getMIDISysExMessage() {
  BYTE_VECTOR *body = new BYTE_VECTOR();
  BYTE_VECTOR *message = new BYTE_VECTOR();
  BYTE_VECTOR *manufacturerHeader = Device::getManufacturerHeader();

  BYTE_VECTOR *md = getMessageData();
  int mdSize = md->size();
  BYTE_VECTOR *bodyLength = MIDI::byteSplit(mdSize, 2);
  BYTE_VECTOR *transactionId = getTransactionId();

  body->reserve(deviceHeader->size() + 6 + mdSize);
  body->insert(body->end(), deviceHeader->begin(), deviceHeader->end());
  body->insert(body->end(), transactionId->begin(), transactionId->end());
  body->insert(body->end(), getCommand()->begin(), getCommand()->end());
  body->insert(body->end(), bodyLength->begin(), bodyLength->end());
  if (mdSize > 0) {
    body->insert(body->end(), md->begin(), md->end());
  }
  unsigned char cs = MIDI::RolandChecksum(body);

  message->reserve(manufacturerHeader->size() + deviceHeader->size() + mdSize +
                   4);
  message->push_back(SYSEX_START);
  message->insert(message->end(), manufacturerHeader->begin(),
                  manufacturerHeader->end());
  message->push_back(Device::MESSAGE_CLASS);
  message->insert(message->end(), body->begin(), body->end());
  message->push_back(cs);
  message->push_back(SYSEX_END);
  return message;
}

SysExMessage::Command SysExMessage::parseAnswer(BYTE_VECTOR *answer) {
  std::cout << "Answer: " << std::dec << answer->size() << std::endl;
  BYTE_VECTOR *commandBytes =
      new BYTE_VECTOR(answer->begin() + 14, answer->begin() + 16);
  MIDISysexValue command = MIDISysexValue(commandBytes);
  if (checkAnswerValid(command.getLongValue())) {
#ifdef __RTMIDI_DEBUG__
    std::cout << "Answer (command: " << command.getLongValue() << ") accepted "
              << std::endl;
#endif //__RTMIDI_DEBUG__
    extractData(answer);
    return (SysExMessage::Command)command.getLongValue();
  }
#ifdef __RTMIDI_DEBUG__
  std::cout << "Answer (command: " << command.getLongValue()
            << ") not accepted " << std::endl;
#endif //__RTMIDI_DEBUG__
  return CMD_ERROR;
}

bool SysExMessage::checkAnswerValid(long answerCommandId) {
  return std::find(acceptedAnswers.begin(), acceptedAnswers.end(),
                   answerCommandId) != acceptedAnswers.end();
}

void SysExMessage::createAnswer(SysExMessage::Command cmd,
                                std::vector<unsigned char> *message,
                                Device *device) {
  if (cmd == ACK) {
    answer = new Ack(cmd, message, device);
    answer->parseAnswerData();
  }
}

int SysExMessage::execute() {
  if (device == 0)
    return -1;
  BYTE_VECTOR *message = getMIDISysExMessage();
  if (debug)
    MIDI::printMessage(message);
  device->sentSysex(message);
  BYTE_VECTOR *answerMessage = device->retrieveSysex();
  if (answerMessage != nullptr) {
    Command cmd = parseAnswer(answerMessage);
    if (debug)
      MIDI::printMessage(answerMessage);
    if (cmd != this->cmd)
      createAnswer(cmd, answerMessage, device);
  }
  return 0;
}

void SysExMessage::setDebug(bool debug) { this->debug = debug; }

void SysExMessage::printRawData() { MIDI::printMessage(data); }

SysExMessage *SysExMessage::getAnswer() { return answer; }

SysExMessage *SysExMessage::query() {
  execute();
  return answer;
}

std::string SysExMessage::getDataAsString() {
  std::string string2(data->begin(), data->end());
  return string2;
}

long SysExMessage::getDataAsLong() {
  long result = -1;
  if (data->size() < 11) {
    result = MIDI::byteJoin(data);
  }
  return result;
}

CommandAcceptedAnswers SysExMessage::commandAcceptedAnswers = {
    {GET_DEVICE, AcceptedAnswers{RET_DEVICE}},
    {GET_COMMAND_LIST, AcceptedAnswers{RET_COMMAND_LIST}},
    {GET_INFO_LIST, AcceptedAnswers{RET_INFO_LIST}},
    {GET_INFO, AcceptedAnswers{RET_SET_INFO}},
    {RET_SET_INFO, AcceptedAnswers{ACK}},
    {GET_RESET_LIST, AcceptedAnswers{RET_RESET_LIST, ACK}},
    {GET_SAVE_RESTORE_LIST, AcceptedAnswers{RET_SAVE_RESTORE_LIST, ACK}},
    {GET_ETHERNET_PORT_INFO, AcceptedAnswers{RET_SET_ETHERNET_PORT_INFO, ACK}},
    {RET_SET_ETHERNET_PORT_INFO, AcceptedAnswers{ACK}},
    {RESET, AcceptedAnswers{ACK}},
    {SAVE_RESTORE, AcceptedAnswers{ACK}},
    {GET_GIZMO_COUNT, AcceptedAnswers{RET_GIZMO_COUNT, ACK}},
    {GET_GIZMO_INFO, AcceptedAnswers{RET_GIZMO_INFO, ACK}},
    {GET_MIDI_INFO, AcceptedAnswers{RET_SET_MIDI_INFO, ACK}},
    {GET_MIDI_PORT_INFO, AcceptedAnswers{RET_SET_MIDI_PORT_INFO}},
    {RET_SET_MIDI_PORT_INFO, AcceptedAnswers{ACK}}};
<commit_msg>GET_MIDI_PORT_INFO can have an ACK message as an answer if something is wrong<commit_after>#include "sysexmessage.h"
#include "ack.h"

#include <algorithm>
#include <iostream>
#include <unistd.h>

/*
 * Structure and naming od sysex data
 *
 * SYSEX_START 1Byte
 * MANUFACTURER_CODE 3Byte--| Header
 * MESSAGE_CLASS 1Byte ------
 *
 * PRODUCT_ID 2Byte --------| DeviceId -
 * SERIAL_NUMBER 5 Byte -----          |
 *                                     |
 * TRANSACTION_ID 2Byte ----|          | Body (Relevant for Checksum)
 * COMMAND 2Byte            |          |
 * DATA_LENGTH 2Byte        |          |
 * COMMAND_DATA xByte -------          |
 *                          -----------|
 * X_SUM 1yte
 *
 * SYSEX_END 1Byte
 *
 * ST| Man.Id |MC| PID | Serial No.   | TID | CID | LEN  | Data|CS|SE
 * 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17   ...  .. ..
 * F0 00 01 73 7E xx xx xx xx xx xx xx xx xx xx xx xx xx  xxxx  xx F7
 */

SysExMessage::SysExMessage(Command cmd, CommandFlags flags, Device *device)
    : cmd(cmd), cmdflags(flags), device(device) {
  if (this->device != 0)
    this->deviceHeader = this->device->getDeviceHeader();
  else
    deviceHeader = new BYTE_VECTOR();
  command = new BYTE_VECTOR();
  command->push_back(flags);
  command->push_back(cmd);
  acceptedAnswers = commandAcceptedAnswers[cmd];
}

SysExMessage::SysExMessage(Command cmd, std::vector<unsigned char> *message,
                           Device *device)
    : cmd(cmd), device(device) {
  if (this->device != 0)
    this->deviceHeader = this->device->getDeviceHeader();
  else
    deviceHeader = new BYTE_VECTOR();
  cmdflags = (*message)[14];
  command = new BYTE_VECTOR();
  command->push_back(cmdflags);
  command->push_back(cmd);
  acceptedAnswers = commandAcceptedAnswers[cmd];
  extractData(message);
}

SysExMessage::~SysExMessage() {
  delete command;
  delete deviceHeader;
}

void SysExMessage::extractData(std::vector<unsigned char> *message) {
  long dataLength = MIDI::byteJoin(
      new BYTE_VECTOR(message->begin() + Device::DATA_LENGTH_OFFSET,
                      message->begin() + Device::DATA_LENGTH_OFFSET +
                          Device::DATA_LENGTH_LENGTH));
  data = new BYTE_VECTOR(message->begin() + Device::DATA_OFFSET,
                         message->begin() + Device::DATA_OFFSET + dataLength);
}

BYTE_VECTOR *SysExMessage::getMIDISysExMessage() {
  BYTE_VECTOR *body = new BYTE_VECTOR();
  BYTE_VECTOR *message = new BYTE_VECTOR();
  BYTE_VECTOR *manufacturerHeader = Device::getManufacturerHeader();

  BYTE_VECTOR *md = getMessageData();
  int mdSize = md->size();
  BYTE_VECTOR *bodyLength = MIDI::byteSplit(mdSize, 2);
  BYTE_VECTOR *transactionId = getTransactionId();

  body->reserve(deviceHeader->size() + 6 + mdSize);
  body->insert(body->end(), deviceHeader->begin(), deviceHeader->end());
  body->insert(body->end(), transactionId->begin(), transactionId->end());
  body->insert(body->end(), getCommand()->begin(), getCommand()->end());
  body->insert(body->end(), bodyLength->begin(), bodyLength->end());
  if (mdSize > 0) {
    body->insert(body->end(), md->begin(), md->end());
  }
  unsigned char cs = MIDI::RolandChecksum(body);

  message->reserve(manufacturerHeader->size() + deviceHeader->size() + mdSize +
                   4);
  message->push_back(SYSEX_START);
  message->insert(message->end(), manufacturerHeader->begin(),
                  manufacturerHeader->end());
  message->push_back(Device::MESSAGE_CLASS);
  message->insert(message->end(), body->begin(), body->end());
  message->push_back(cs);
  message->push_back(SYSEX_END);
  return message;
}

SysExMessage::Command SysExMessage::parseAnswer(BYTE_VECTOR *answer) {
  std::cout << "Answer: " << std::dec << answer->size() << std::endl;
  BYTE_VECTOR *commandBytes =
      new BYTE_VECTOR(answer->begin() + 14, answer->begin() + 16);
  MIDISysexValue command = MIDISysexValue(commandBytes);
  if (checkAnswerValid(command.getLongValue())) {
#ifdef __RTMIDI_DEBUG__
    std::cout << "Answer (command: " << command.getLongValue() << ") accepted "
              << std::endl;
#endif //__RTMIDI_DEBUG__
    extractData(answer);
    return (SysExMessage::Command)command.getLongValue();
  }
#ifdef __RTMIDI_DEBUG__
  std::cout << "Answer (command: " << command.getLongValue()
            << ") not accepted " << std::endl;
#endif //__RTMIDI_DEBUG__
  return CMD_ERROR;
}

bool SysExMessage::checkAnswerValid(long answerCommandId) {
  return std::find(acceptedAnswers.begin(), acceptedAnswers.end(),
                   answerCommandId) != acceptedAnswers.end();
}

void SysExMessage::createAnswer(SysExMessage::Command cmd,
                                std::vector<unsigned char> *message,
                                Device *device) {
  if (cmd == ACK) {
    answer = new Ack(cmd, message, device);
    answer->parseAnswerData();
  }
}

int SysExMessage::execute() {
  if (device == 0)
    return -1;
  BYTE_VECTOR *message = getMIDISysExMessage();
  if (debug)
    MIDI::printMessage(message);
  device->sentSysex(message);
  BYTE_VECTOR *answerMessage = device->retrieveSysex();
  if (answerMessage != nullptr) {
    Command cmd = parseAnswer(answerMessage);
    if (debug)
      MIDI::printMessage(answerMessage);
    if (cmd != this->cmd)
      createAnswer(cmd, answerMessage, device);
  }
  return 0;
}

void SysExMessage::setDebug(bool debug) { this->debug = debug; }

void SysExMessage::printRawData() { MIDI::printMessage(data); }

SysExMessage *SysExMessage::getAnswer() { return answer; }

SysExMessage *SysExMessage::query() {
  execute();
  return answer;
}

std::string SysExMessage::getDataAsString() {
  std::string string2(data->begin(), data->end());
  return string2;
}

long SysExMessage::getDataAsLong() {
  long result = -1;
  if (data->size() < 11) {
    result = MIDI::byteJoin(data);
  }
  return result;
}

CommandAcceptedAnswers SysExMessage::commandAcceptedAnswers = {
    {GET_DEVICE, AcceptedAnswers{RET_DEVICE}},
    {GET_COMMAND_LIST, AcceptedAnswers{RET_COMMAND_LIST}},
    {GET_INFO_LIST, AcceptedAnswers{RET_INFO_LIST}},
    {GET_INFO, AcceptedAnswers{RET_SET_INFO}},
    {RET_SET_INFO, AcceptedAnswers{ACK}},
    {GET_RESET_LIST, AcceptedAnswers{RET_RESET_LIST, ACK}},
    {GET_SAVE_RESTORE_LIST, AcceptedAnswers{RET_SAVE_RESTORE_LIST, ACK}},
    {GET_ETHERNET_PORT_INFO, AcceptedAnswers{RET_SET_ETHERNET_PORT_INFO, ACK}},
    {RET_SET_ETHERNET_PORT_INFO, AcceptedAnswers{ACK}},
    {RESET, AcceptedAnswers{ACK}},
    {SAVE_RESTORE, AcceptedAnswers{ACK}},
    {GET_GIZMO_COUNT, AcceptedAnswers{RET_GIZMO_COUNT, ACK}},
    {GET_GIZMO_INFO, AcceptedAnswers{RET_GIZMO_INFO, ACK}},
    {GET_MIDI_INFO, AcceptedAnswers{RET_SET_MIDI_INFO, ACK}},
		{GET_MIDI_PORT_INFO, AcceptedAnswers{RET_SET_MIDI_PORT_INFO, ACK}},
    {RET_SET_MIDI_PORT_INFO, AcceptedAnswers{ACK}}};
<|endoftext|>