<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: atom.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 14:08:09 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <unotools/atom.hxx>

using namespace utl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
#define NMSP_UTIL ::com::sun::star::util

AtomProvider::AtomProvider()
{
    m_nAtoms = 1;
}

AtomProvider::~AtomProvider()
{
}

int AtomProvider::getAtom( const ::rtl::OUString& rString, sal_Bool bCreate )
{
    ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::iterator it = m_aAtomMap.find( rString );
    if( it != m_aAtomMap.end() )
        return it->second;
    if( ! bCreate )
        return INVALID_ATOM;
    m_aAtomMap[ rString ] = m_nAtoms;
    m_aStringMap[ m_nAtoms ] = rString;
    m_nAtoms++;
    return m_nAtoms-1;
}

void AtomProvider::getAll( ::std::list< ::utl::AtomDescription >& atoms )
{
    atoms.clear();
    ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::const_iterator it = m_aAtomMap.begin();

    ::utl::AtomDescription aDesc;
    while( it != m_aAtomMap.end() )
    {
        aDesc.atom          = it->second;
        aDesc.description   = it->first;
        atoms.push_back( aDesc );
        ++it;
    }
}

void AtomProvider::getRecent( int atom, ::std::list< ::utl::AtomDescription >& atoms )
{
    atoms.clear();

    ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::const_iterator it = m_aAtomMap.begin();

    ::utl::AtomDescription aDesc;
    while( it != m_aAtomMap.end() )
    {
        if( it->second > atom )
        {
            aDesc.atom          = it->second;
            aDesc.description   = it->first;
            atoms.push_back( aDesc );
        }
        ++it;
    }
}

const ::rtl::OUString& AtomProvider::getString( int nAtom ) const
{
    static ::rtl::OUString aEmpty;
    ::std::hash_map< int, ::rtl::OUString, ::std::hash< int > >::const_iterator it = m_aStringMap.find( nAtom );

    return it == m_aStringMap.end() ? aEmpty : it->second;
}

void AtomProvider::overrideAtom( int atom, const ::rtl::OUString& description )
{
    m_aAtomMap[ description ] = atom;
    m_aStringMap[ atom ] = description;
    if( m_nAtoms <= atom )
        m_nAtoms=atom+1;
}

sal_Bool AtomProvider::hasAtom( int atom ) const
{
    return m_aStringMap.find( atom ) != m_aStringMap.end() ? sal_True : sal_False;
}

// -----------------------------------------------------------------------

MultiAtomProvider::MultiAtomProvider()
{
}

MultiAtomProvider::~MultiAtomProvider()
{
    for( ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it = m_aAtomLists.begin(); it != m_aAtomLists.end(); ++it )
        delete it->second;
}

sal_Bool MultiAtomProvider::insertAtomClass( int atomClass )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        return sal_False;
    m_aAtomLists[ atomClass ] = new AtomProvider();
    return sal_True;
}

int MultiAtomProvider::getAtom( int atomClass, const ::rtl::OUString& rString, sal_Bool bCreate )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        return it->second->getAtom( rString, bCreate );

    if( bCreate )
    {
        AtomProvider* pNewClass;
        m_aAtomLists[ atomClass ] = pNewClass = new AtomProvider();
        return pNewClass->getAtom( rString, bCreate );
    }
    return INVALID_ATOM;
}

int MultiAtomProvider::getLastAtom( int atomClass ) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it =
          m_aAtomLists.find( atomClass );

    return it != m_aAtomLists.end() ? it->second->getLastAtom() : INVALID_ATOM;
}

void MultiAtomProvider::getRecent( int atomClass, int atom, ::std::list< ::utl::AtomDescription >& atoms )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        it->second->getRecent( atom, atoms );
    else
        atoms.clear();
}

const ::rtl::OUString& MultiAtomProvider::getString( int atomClass, int atom ) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        return it->second->getString( atom );

    static ::rtl::OUString aEmpty;
    return aEmpty;
}

sal_Bool MultiAtomProvider::hasAtom( int atomClass, int atom ) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass );
    return it != m_aAtomLists.end() ? it->second->hasAtom( atom ) : sal_False;
}

void MultiAtomProvider::getClass( int atomClass, ::std::list< ::utl::AtomDescription >& atoms) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass );

    if( it != m_aAtomLists.end() )
        it->second->getAll( atoms );
    else
        atoms.clear();
}

void MultiAtomProvider::overrideAtom( int atomClass, int atom, const ::rtl::OUString& description )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass );
    if( it == m_aAtomLists.end() )
        m_aAtomLists[ atomClass ] = new AtomProvider();
    m_aAtomLists[ atomClass ]->overrideAtom( atom, description );
}

// -----------------------------------------------------------------------

AtomServer::AtomServer()
{
}

AtomServer::~AtomServer()
{
}

sal_Int32 AtomServer::getAtom( sal_Int32 atomClass, const ::rtl::OUString& description, sal_Bool create ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    return m_aProvider.getAtom( atomClass, description, create );
}

Sequence< Sequence< NMSP_UTIL::AtomDescription > > AtomServer::getClasses( const Sequence< sal_Int32 >& atomClasses ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    Sequence< Sequence< NMSP_UTIL::AtomDescription > > aRet( atomClasses.getLength() );
    for( int i = 0; i < atomClasses.getLength(); i++ )
    {
        aRet.getArray()[i] = getClass( atomClasses.getConstArray()[i] );
    }
    return aRet;
}

Sequence< NMSP_UTIL::AtomDescription > AtomServer::getClass( sal_Int32 atomClass ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    ::std::list< ::utl::AtomDescription > atoms;
    m_aProvider.getClass( atomClass, atoms );

    Sequence< NMSP_UTIL::AtomDescription > aRet( atoms.size() );
    for( int i = aRet.getLength()-1; i >= 0; i-- )
    {
        aRet.getArray()[i].atom         = atoms.back().atom;
        aRet.getArray()[i].description  = atoms.back().description;
        atoms.pop_back();
    }

    return aRet;
}

Sequence< NMSP_UTIL::AtomDescription > AtomServer::getRecentAtoms( sal_Int32 atomClass, sal_Int32 atom ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    ::std::list< ::utl::AtomDescription > atoms;
    m_aProvider.getRecent( atomClass, atom, atoms );

    Sequence< NMSP_UTIL::AtomDescription > aRet( atoms.size() );
    for( int i = aRet.getLength()-1; i >= 0; i-- )
    {
        aRet.getArray()[i].atom         = atoms.back().atom;
        aRet.getArray()[i].description  = atoms.back().description;
        atoms.pop_back();
    }

    return aRet;
}

Sequence< ::rtl::OUString > AtomServer::getAtomDescriptions( const Sequence< AtomClassRequest >& atoms ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    int nStrings = 0, i;
    for( i = 0; i < atoms.getLength(); i++ )
        nStrings += atoms.getConstArray()[ i ].atoms.getLength();
    Sequence< ::rtl::OUString > aRet( nStrings );
    for( i = 0, nStrings = 0; i < atoms.getLength(); i++ )
    {
        const AtomClassRequest& rRequest = atoms.getConstArray()[i];
        for( int n = 0; n < rRequest.atoms.getLength(); n++ )
            aRet.getArray()[ nStrings++ ] = m_aProvider.getString( rRequest.atomClass, rRequest.atoms.getConstArray()[ n ] );
    }
    return aRet;
}

// -----------------------------------------------------------------------

AtomClient::AtomClient( const Reference< XAtomServer >& xServer ) :
        m_xServer( xServer )
{
}

AtomClient::~AtomClient()
{
}

int AtomClient::getAtom( int atomClass, const ::rtl::OUString& description, sal_Bool bCreate )
{
    int nAtom = m_aProvider.getAtom( atomClass, description, sal_False );
    if( nAtom == INVALID_ATOM && bCreate )
    {
        try
        {
            nAtom = m_xServer->getAtom( atomClass, description, bCreate );
        }
        catch( RuntimeException& )
        {
            return INVALID_ATOM;
        }
        if( nAtom != INVALID_ATOM )
            m_aProvider.overrideAtom( atomClass, nAtom, description );
    }
    return nAtom;
}

const ::rtl::OUString& AtomClient::getString( int atomClass, int atom )
{
    static ::rtl::OUString aEmpty;

    if( ! m_aProvider.hasAtom( atomClass, atom ) )
    {
        Sequence< NMSP_UTIL::AtomDescription > aSeq;
        try
        {
            aSeq = m_xServer->getRecentAtoms( atomClass, m_aProvider.getLastAtom( atomClass ) );
        }
        catch( RuntimeException& )
        {
            return aEmpty;
        }
        const NMSP_UTIL::AtomDescription* pDescriptions = aSeq.getConstArray();
        for( int i = 0; i < aSeq.getLength(); i++ )
            m_aProvider.overrideAtom( atomClass,
                                      pDescriptions[i].atom,
                                      pDescriptions[i].description
                                      );

        if( ! m_aProvider.hasAtom( atomClass, atom ) )
        {
            // holes may occur by the above procedure!
            Sequence< AtomClassRequest > aReq( 1 );
            aReq.getArray()[0].atomClass = atomClass;
            aReq.getArray()[0].atoms.realloc( 1 );
            aReq.getArray()[0].atoms.getArray()[0] = atom;
            Sequence< ::rtl::OUString > aRet;
            try
            {
                aRet = m_xServer->getAtomDescriptions( aReq );
            }
            catch( RuntimeException& )
            {
                return aEmpty;
            }
            if( aRet.getLength() == 1 )
                m_aProvider.overrideAtom( atomClass, atom, aRet.getConstArray()[0] );
        }
    }
    return m_aProvider.getString( atomClass, atom );
}

void AtomClient::updateAtomClasses( const Sequence< sal_Int32 >& atomClasses )
{
    Sequence< Sequence< NMSP_UTIL::AtomDescription > > aUpdate;
    try
    {
        aUpdate = m_xServer->getClasses( atomClasses );
    }
    catch( RuntimeException& )
    {
        return;
    }
    for( int i = 0; i < atomClasses.getLength(); i++ )
    {
        int nClass = atomClasses.getConstArray()[i];
        const Sequence< NMSP_UTIL::AtomDescription >& rClass = aUpdate.getConstArray()[i];
        const NMSP_UTIL::AtomDescription* pDesc = rClass.getConstArray();
        for( int n = 0; n < rClass.getLength(); n++, pDesc++ )
            m_aProvider.overrideAtom( nClass, pDesc->atom, pDesc->description );
    }
}
<commit_msg>INTEGRATION: CWS pchfix02 (1.8.16); FILE MERGED 2006/09/01 17:56:23 kaib 1.8.16.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: atom.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 01:26:43 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_unotools.hxx"

#include <unotools/atom.hxx>

using namespace utl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
#define NMSP_UTIL ::com::sun::star::util

AtomProvider::AtomProvider()
{
    m_nAtoms = 1;
}

AtomProvider::~AtomProvider()
{
}

int AtomProvider::getAtom( const ::rtl::OUString& rString, sal_Bool bCreate )
{
    ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::iterator it = m_aAtomMap.find( rString );
    if( it != m_aAtomMap.end() )
        return it->second;
    if( ! bCreate )
        return INVALID_ATOM;
    m_aAtomMap[ rString ] = m_nAtoms;
    m_aStringMap[ m_nAtoms ] = rString;
    m_nAtoms++;
    return m_nAtoms-1;
}

void AtomProvider::getAll( ::std::list< ::utl::AtomDescription >& atoms )
{
    atoms.clear();
    ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::const_iterator it = m_aAtomMap.begin();

    ::utl::AtomDescription aDesc;
    while( it != m_aAtomMap.end() )
    {
        aDesc.atom          = it->second;
        aDesc.description   = it->first;
        atoms.push_back( aDesc );
        ++it;
    }
}

void AtomProvider::getRecent( int atom, ::std::list< ::utl::AtomDescription >& atoms )
{
    atoms.clear();

    ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::const_iterator it = m_aAtomMap.begin();

    ::utl::AtomDescription aDesc;
    while( it != m_aAtomMap.end() )
    {
        if( it->second > atom )
        {
            aDesc.atom          = it->second;
            aDesc.description   = it->first;
            atoms.push_back( aDesc );
        }
        ++it;
    }
}

const ::rtl::OUString& AtomProvider::getString( int nAtom ) const
{
    static ::rtl::OUString aEmpty;
    ::std::hash_map< int, ::rtl::OUString, ::std::hash< int > >::const_iterator it = m_aStringMap.find( nAtom );

    return it == m_aStringMap.end() ? aEmpty : it->second;
}

void AtomProvider::overrideAtom( int atom, const ::rtl::OUString& description )
{
    m_aAtomMap[ description ] = atom;
    m_aStringMap[ atom ] = description;
    if( m_nAtoms <= atom )
        m_nAtoms=atom+1;
}

sal_Bool AtomProvider::hasAtom( int atom ) const
{
    return m_aStringMap.find( atom ) != m_aStringMap.end() ? sal_True : sal_False;
}

// -----------------------------------------------------------------------

MultiAtomProvider::MultiAtomProvider()
{
}

MultiAtomProvider::~MultiAtomProvider()
{
    for( ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it = m_aAtomLists.begin(); it != m_aAtomLists.end(); ++it )
        delete it->second;
}

sal_Bool MultiAtomProvider::insertAtomClass( int atomClass )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        return sal_False;
    m_aAtomLists[ atomClass ] = new AtomProvider();
    return sal_True;
}

int MultiAtomProvider::getAtom( int atomClass, const ::rtl::OUString& rString, sal_Bool bCreate )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        return it->second->getAtom( rString, bCreate );

    if( bCreate )
    {
        AtomProvider* pNewClass;
        m_aAtomLists[ atomClass ] = pNewClass = new AtomProvider();
        return pNewClass->getAtom( rString, bCreate );
    }
    return INVALID_ATOM;
}

int MultiAtomProvider::getLastAtom( int atomClass ) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it =
          m_aAtomLists.find( atomClass );

    return it != m_aAtomLists.end() ? it->second->getLastAtom() : INVALID_ATOM;
}

void MultiAtomProvider::getRecent( int atomClass, int atom, ::std::list< ::utl::AtomDescription >& atoms )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        it->second->getRecent( atom, atoms );
    else
        atoms.clear();
}

const ::rtl::OUString& MultiAtomProvider::getString( int atomClass, int atom ) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it =
          m_aAtomLists.find( atomClass );
    if( it != m_aAtomLists.end() )
        return it->second->getString( atom );

    static ::rtl::OUString aEmpty;
    return aEmpty;
}

sal_Bool MultiAtomProvider::hasAtom( int atomClass, int atom ) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass );
    return it != m_aAtomLists.end() ? it->second->hasAtom( atom ) : sal_False;
}

void MultiAtomProvider::getClass( int atomClass, ::std::list< ::utl::AtomDescription >& atoms) const
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass );

    if( it != m_aAtomLists.end() )
        it->second->getAll( atoms );
    else
        atoms.clear();
}

void MultiAtomProvider::overrideAtom( int atomClass, int atom, const ::rtl::OUString& description )
{
    ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass );
    if( it == m_aAtomLists.end() )
        m_aAtomLists[ atomClass ] = new AtomProvider();
    m_aAtomLists[ atomClass ]->overrideAtom( atom, description );
}

// -----------------------------------------------------------------------

AtomServer::AtomServer()
{
}

AtomServer::~AtomServer()
{
}

sal_Int32 AtomServer::getAtom( sal_Int32 atomClass, const ::rtl::OUString& description, sal_Bool create ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    return m_aProvider.getAtom( atomClass, description, create );
}

Sequence< Sequence< NMSP_UTIL::AtomDescription > > AtomServer::getClasses( const Sequence< sal_Int32 >& atomClasses ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    Sequence< Sequence< NMSP_UTIL::AtomDescription > > aRet( atomClasses.getLength() );
    for( int i = 0; i < atomClasses.getLength(); i++ )
    {
        aRet.getArray()[i] = getClass( atomClasses.getConstArray()[i] );
    }
    return aRet;
}

Sequence< NMSP_UTIL::AtomDescription > AtomServer::getClass( sal_Int32 atomClass ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    ::std::list< ::utl::AtomDescription > atoms;
    m_aProvider.getClass( atomClass, atoms );

    Sequence< NMSP_UTIL::AtomDescription > aRet( atoms.size() );
    for( int i = aRet.getLength()-1; i >= 0; i-- )
    {
        aRet.getArray()[i].atom         = atoms.back().atom;
        aRet.getArray()[i].description  = atoms.back().description;
        atoms.pop_back();
    }

    return aRet;
}

Sequence< NMSP_UTIL::AtomDescription > AtomServer::getRecentAtoms( sal_Int32 atomClass, sal_Int32 atom ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    ::std::list< ::utl::AtomDescription > atoms;
    m_aProvider.getRecent( atomClass, atom, atoms );

    Sequence< NMSP_UTIL::AtomDescription > aRet( atoms.size() );
    for( int i = aRet.getLength()-1; i >= 0; i-- )
    {
        aRet.getArray()[i].atom         = atoms.back().atom;
        aRet.getArray()[i].description  = atoms.back().description;
        atoms.pop_back();
    }

    return aRet;
}

Sequence< ::rtl::OUString > AtomServer::getAtomDescriptions( const Sequence< AtomClassRequest >& atoms ) throw()
{
    ::osl::Guard< ::osl::Mutex > guard( m_aMutex );

    int nStrings = 0, i;
    for( i = 0; i < atoms.getLength(); i++ )
        nStrings += atoms.getConstArray()[ i ].atoms.getLength();
    Sequence< ::rtl::OUString > aRet( nStrings );
    for( i = 0, nStrings = 0; i < atoms.getLength(); i++ )
    {
        const AtomClassRequest& rRequest = atoms.getConstArray()[i];
        for( int n = 0; n < rRequest.atoms.getLength(); n++ )
            aRet.getArray()[ nStrings++ ] = m_aProvider.getString( rRequest.atomClass, rRequest.atoms.getConstArray()[ n ] );
    }
    return aRet;
}

// -----------------------------------------------------------------------

AtomClient::AtomClient( const Reference< XAtomServer >& xServer ) :
        m_xServer( xServer )
{
}

AtomClient::~AtomClient()
{
}

int AtomClient::getAtom( int atomClass, const ::rtl::OUString& description, sal_Bool bCreate )
{
    int nAtom = m_aProvider.getAtom( atomClass, description, sal_False );
    if( nAtom == INVALID_ATOM && bCreate )
    {
        try
        {
            nAtom = m_xServer->getAtom( atomClass, description, bCreate );
        }
        catch( RuntimeException& )
        {
            return INVALID_ATOM;
        }
        if( nAtom != INVALID_ATOM )
            m_aProvider.overrideAtom( atomClass, nAtom, description );
    }
    return nAtom;
}

const ::rtl::OUString& AtomClient::getString( int atomClass, int atom )
{
    static ::rtl::OUString aEmpty;

    if( ! m_aProvider.hasAtom( atomClass, atom ) )
    {
        Sequence< NMSP_UTIL::AtomDescription > aSeq;
        try
        {
            aSeq = m_xServer->getRecentAtoms( atomClass, m_aProvider.getLastAtom( atomClass ) );
        }
        catch( RuntimeException& )
        {
            return aEmpty;
        }
        const NMSP_UTIL::AtomDescription* pDescriptions = aSeq.getConstArray();
        for( int i = 0; i < aSeq.getLength(); i++ )
            m_aProvider.overrideAtom( atomClass,
                                      pDescriptions[i].atom,
                                      pDescriptions[i].description
                                      );

        if( ! m_aProvider.hasAtom( atomClass, atom ) )
        {
            // holes may occur by the above procedure!
            Sequence< AtomClassRequest > aReq( 1 );
            aReq.getArray()[0].atomClass = atomClass;
            aReq.getArray()[0].atoms.realloc( 1 );
            aReq.getArray()[0].atoms.getArray()[0] = atom;
            Sequence< ::rtl::OUString > aRet;
            try
            {
                aRet = m_xServer->getAtomDescriptions( aReq );
            }
            catch( RuntimeException& )
            {
                return aEmpty;
            }
            if( aRet.getLength() == 1 )
                m_aProvider.overrideAtom( atomClass, atom, aRet.getConstArray()[0] );
        }
    }
    return m_aProvider.getString( atomClass, atom );
}

void AtomClient::updateAtomClasses( const Sequence< sal_Int32 >& atomClasses )
{
    Sequence< Sequence< NMSP_UTIL::AtomDescription > > aUpdate;
    try
    {
        aUpdate = m_xServer->getClasses( atomClasses );
    }
    catch( RuntimeException& )
    {
        return;
    }
    for( int i = 0; i < atomClasses.getLength(); i++ )
    {
        int nClass = atomClasses.getConstArray()[i];
        const Sequence< NMSP_UTIL::AtomDescription >& rClass = aUpdate.getConstArray()[i];
        const NMSP_UTIL::AtomDescription* pDesc = rClass.getConstArray();
        for( int n = 0; n < rClass.getLength(); n++, pDesc++ )
            m_aProvider.overrideAtom( nClass, pDesc->atom, pDesc->description );
    }
}
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

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

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

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

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

#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>
#include "mitkIOUtil.h"
#include <cmath>

#include <mitkGIFFirstOrderNumericStatistics.h>

class mitkGIFFirstOrderNumericStatisticsTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkGIFFirstOrderNumericStatisticsTestSuite);

  MITK_TEST(ImageDescription_PhantomTest);

  CPPUNIT_TEST_SUITE_END();

private:
  mitk::Image::Pointer m_IBSI_Phantom_Image_Small;
  mitk::Image::Pointer m_IBSI_Phantom_Image_Large;
  mitk::Image::Pointer m_IBSI_Phantom_Mask_Small;
  mitk::Image::Pointer m_IBSI_Phantom_Mask_Large;

public:

  void setUp(void) override
  {
    m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd"));
    m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd"));
    m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd"));
    m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd"));
  }

  void ImageDescription_PhantomTest()
  {
    mitk::GIFFirstOrderNumericStatistics::Pointer featureCalculator = mitk::GIFFirstOrderNumericStatistics::New();

    featureCalculator->SetUseBinsize(true);
    featureCalculator->SetBinsize(1.0);
    featureCalculator->SetUseMinimumIntensity(true);
    featureCalculator->SetUseMaximumIntensity(true);
    featureCalculator->SetMinimumIntensity(0.5);
    featureCalculator->SetMaximumIntensity(6.5);

    auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large);

    std::map<std::string, double> results;
    for (auto valuePair : featureList)
    {
      MITK_INFO << valuePair.first << " : " << valuePair.second;
      results[valuePair.first] = valuePair.second;
    }
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 46 features.", std::size_t(46), featureList.size());

    // These values are obtained by a run of the filter.
    // The might be wrong!
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Value should be 2.15 with Large IBSI Phantom Image", 2.15, results["First Order Histogram::Mean Value"], 0.01);

    // These values are taken from the IBSI Initiative to ensure compatibility
    // The values are given with an accuracy of 0.01
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Index should be 2.15 with Large IBSI Phantom Image", 2.15, results["First Order Histogram::Mean Index"], 0.01);

  }

};

MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderNumericStatistics )<commit_msg>All relevant tested<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

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

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

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

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

#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>
#include "mitkIOUtil.h"
#include <cmath>

#include <mitkGIFFirstOrderNumericStatistics.h>

class mitkGIFFirstOrderNumericStatisticsTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkGIFFirstOrderNumericStatisticsTestSuite);

  MITK_TEST(ImageDescription_PhantomTest);

  CPPUNIT_TEST_SUITE_END();

private:
  mitk::Image::Pointer m_IBSI_Phantom_Image_Small;
  mitk::Image::Pointer m_IBSI_Phantom_Image_Large;
  mitk::Image::Pointer m_IBSI_Phantom_Mask_Small;
  mitk::Image::Pointer m_IBSI_Phantom_Mask_Large;

public:

  void setUp(void) override
  {
    m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd"));
    m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd"));
    m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd"));
    m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load<mitk::Image>(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd"));
  }

  void ImageDescription_PhantomTest()
  {
    mitk::GIFFirstOrderNumericStatistics::Pointer featureCalculator = mitk::GIFFirstOrderNumericStatistics::New();

    featureCalculator->SetUseBinsize(true);
    featureCalculator->SetBinsize(1.0);
    featureCalculator->SetUseMinimumIntensity(true);
    featureCalculator->SetUseMaximumIntensity(true);
    featureCalculator->SetMinimumIntensity(0.5);
    featureCalculator->SetMaximumIntensity(6.5);

    auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large);

    std::map<std::string, double> results;
    for (auto valuePair : featureList)
    {
      MITK_INFO << valuePair.first << " : " << valuePair.second;
      results[valuePair.first] = valuePair.second;
    }
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size());

    // These values are obtained by a run of the filter.
    // The might be wrong!
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean with Large IBSI Phantom Image", 2.15, results["First Order Numeric::Mean"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Variance with Large IBSI Phantom Image", 3.05, results["First Order Numeric::Variance"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Skewness with Large IBSI Phantom Image", 1.08, results["First Order Numeric::Skewness"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Excess kurtosis with Large IBSI Phantom Image", -0.355, results["First Order Numeric::Excess kurtosis"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median with Large IBSI Phantom Image", 1, results["First Order Numeric::Median"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Minimum with Large IBSI Phantom Image", 1, results["First Order Numeric::Minimum"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::10th Percentile with Large IBSI Phantom Image", 1, results["First Order Numeric::10th Percentile"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::90th Percentile with Large IBSI Phantom Image", 4, results["First Order Numeric::90th Percentile"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Maximum with Large IBSI Phantom Image", 6, results["First Order Numeric::Maximum"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Interquantile range with Large IBSI Phantom Image", 3, results["First Order Numeric::Interquantile range"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Range with Large IBSI Phantom Image", 5, results["First Order Numeric::Range"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean absolute deviation with Large IBSI Phantom Image", 1.55, results["First Order Numeric::Mean absolute deviation"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean absolute deviation with Large IBSI Phantom Image", 1.11, results["First Order Numeric::Robust mean absolute deviation"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median absolute deviation with Large IBSI Phantom Image", 1.15, results["First Order Numeric::Median absolute deviation"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order Numeric::Coefficient of variation"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.6, results["First Order Numeric::Quantile coefficient of dispersion"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Energy with Large IBSI Phantom Image", 567, results["First Order Numeric::Energy"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order Numeric::Root mean square"], 0.01);

    // These values are taken from the IBSI Initiative to ensure compatibility
    // The values are given with an accuracy of 0.01
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Standard Deviation with Large IBSI Phantom Image", 1.74513, results["First Order Numeric::Standard Deviation"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Kurtosis with Large IBSI Phantom Image", 2.64538, results["First Order Numeric::Kurtosis"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order Numeric::Robust mean"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust variance with Large IBSI Phantom Image", 1.65204, results["First Order Numeric::Robust variance"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Covered image intensity range with Large IBSI Phantom Image", 1.2, results["First Order Numeric::Covered image intensity range"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode index with Large IBSI Phantom Image",0 , results["First Order Numeric::Mode index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode value with Large IBSI Phantom Image", 1, results["First Order Numeric::Mode value"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode probability with Large IBSI Phantom Image", 0.675676, results["First Order Numeric::Mode probability"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Entropy with Large IBSI Phantom Image", -1.26561, results["First Order Numeric::Entropy"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Uniformtiy with Large IBSI Phantom Image", 0.512418, results["First Order Numeric::Uniformtiy"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Number of voxels with Large IBSI Phantom Image", 74 , results["First Order Numeric::Number of voxels"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order Numeric::Sum of voxels"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel space with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel space"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel volume with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel volume"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Image Dimension with Large IBSI Phantom Image", 3, results["First Order Numeric::Image Dimension"], 0.01);

  }

};

MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderNumericStatistics )<|endoftext|>


<commit_before>#ifdef ENABLE_LLVM

#if RBX_LLVM_API_VER >= 302
#include <llvm/DataLayout.h>
#else
#include <llvm/Target/TargetData.h>
#endif
#include <llvm/Transforms/Scalar.h>

#include "llvm/state.hpp"
#include "llvm/jit_context.hpp"
#include "llvm/jit_runtime.hpp"
#include "llvm/jit_memory_manager.hpp"
#include "llvm/passes.hpp"

#include "machine_code.hpp"

using namespace llvm;

namespace autogen_types {
  void makeLLVMModuleContents(llvm::Module* module);
}

namespace rubinius {

  Context::Context(LLVMState* ls)
    : ls_(ls)
    , root_info_(0)
    , inlined_block_(false)
    , inline_depth_(0)
    , rds_(new jit::RuntimeDataHolder)
    , function_(0)
    , vm_(0)
    , out_args_(0)
    , counter_(0)
  {
    VoidTy = Type::getVoidTy(ctx_);

    Int1Ty = Type::getInt1Ty(ctx_);
    Int8Ty = Type::getInt8Ty(ctx_);
    Int16Ty = Type::getInt16Ty(ctx_);
    Int32Ty = Type::getInt32Ty(ctx_);
    Int64Ty = Type::getInt64Ty(ctx_);

#ifdef IS_X8664
    IntPtrTy = Int64Ty;
#else
    IntPtrTy = Int32Ty;
#endif

    VoidPtrTy = llvm::PointerType::getUnqual(Int8Ty);

    FloatTy = Type::getFloatTy(ctx_);
    DoubleTy = Type::getDoubleTy(ctx_);

    Int8PtrTy = llvm::PointerType::getUnqual(Int8Ty);

    Zero = llvm::ConstantInt::get(Int32Ty, 0);
    One = llvm::ConstantInt::get(Int32Ty, 1);

    module_ = new llvm::Module("rubinius", ctx_);

    autogen_types::makeLLVMModuleContents(module_);

    llvm::EngineBuilder factory(module_);

    factory.setAllocateGVsWithCode(false);
    memory_ = new jit::RubiniusRequestJITMemoryManager(ls->memory());
    factory.setJITMemoryManager(memory_);

#if RBX_LLVM_API_VER > 300
    llvm::TargetOptions opts;
    opts.NoFramePointerElim = true;
    opts.NoFramePointerElimNonLeaf = true;

    factory.setTargetOptions(opts);
#endif

    engine_ = factory.create();

    builder_ = new llvm::PassManagerBuilder();
    builder_->OptLevel = 2;
    passes_ = new llvm::FunctionPassManager(module_);

#if RBX_LLVM_API_VER >= 302
    module_->setDataLayout(engine_->getDataLayout()->getStringRepresentation());
    passes_->add(new llvm::DataLayout(*engine_->getDataLayout()));
#else
    module_->setDataLayout(engine_->getTargetData()->getStringRepresentation());
    passes_->add(new llvm::TargetData(*engine_->getTargetData()));
#endif

    builder_->populateFunctionPassManager(*passes_);

    // Eliminate unnecessary alloca.
    passes_->add(createPromoteMemoryToRegisterPass());
    // Do simple "peephole" optimizations and bit-twiddling optzns.
    passes_->add(createInstructionCombiningPass());
    // Reassociate expressions.
    passes_->add(createReassociatePass());
    // Eliminate Common SubExpressions.
    passes_->add(createGVNPass());
    passes_->add(createDeadStoreEliminationPass());

    passes_->add(createInstructionCombiningPass());

    // Simplify the control flow graph (deleting unreachable blocks, etc).
    passes_->add(createCFGSimplificationPass());

    passes_->add(create_rubinius_alias_analysis());
    passes_->add(createGVNPass());
    // passes_->add(createCFGSimplificationPass());
    passes_->add(createDeadStoreEliminationPass());
    // passes_->add(createVerifierPass());
    passes_->add(createScalarReplAggregatesPass());

    passes_->add(create_overflow_folding_pass());
    passes_->add(create_guard_eliminator_pass());

    passes_->add(createCFGSimplificationPass());
    passes_->add(createInstructionCombiningPass());
    passes_->add(createScalarReplAggregatesPass());
    passes_->add(createDeadStoreEliminationPass());
    passes_->add(createCFGSimplificationPass());
    passes_->add(createInstructionCombiningPass());
    passes_->doInitialization();

    ObjTy = ptr_type("Object");

    profiling_ = new GlobalVariable(
        *module_, Int1Ty, false,
        GlobalVariable::ExternalLinkage,
        0, "profiling_flag");

    metadata_id_ = ctx_.getMDKindID("rbx-classid");
  }

  Context::~Context() {
    delete builder_;
    delete passes_;
    delete engine_;
    // Memory is cleaned up by the engine
    memory_ = NULL;
  }

  void* Context::native_function() {
    void* addr = memory_->generatedFunction();
    memory_->resetGeneratedFunction();

    engine_->freeMachineCodeForFunction(function_);

    // Nuke the Function from the module
    function_->replaceAllUsesWith(UndefValue::get(function_->getType()));
    function_->removeFromParent();
    return addr;
  }

  llvm::Type* Context::ptr_type(std::string name) {
    std::string full_name = std::string("struct.rubinius::") + name;
    return llvm::PointerType::getUnqual(
        module_->getTypeByName(full_name));
  }

  llvm::Type* Context::type(std::string name) {
    std::string full_name = std::string("struct.rubinius::") + name;
    return module_->getTypeByName(full_name);
  }

  void Context::init_variables(llvm::IRBuilder<>& b) {
    counter_ = b.CreateAlloca(Int32Ty, 0, "counter_alloca");
    out_args_ = b.CreateAlloca(type("Arguments"), 0, "out_args");
  }

  void Context::add_runtime_data(jit::RuntimeData* rd) {
    rds_->add_runtime_data(rd);
  }

  std::ostream& Context::inline_log(const char* header) {
    std::ostream& l = ls_->log();

    for(int i = 0; i <= inline_depth_; i++) {
      l << "|";
    }

    l << " " << header << ": ";
    return l;
  }

  void Context::info(const char* msg) {
    if(!ls_->config().jit_inline_debug) return;

    std::ostream& l = ls_->log();

    for(int i = 0; i <= inline_depth_ - 1; i++) {
      l << "|";
    }

    l << "+ " << msg << "\n";
  }

  std::ostream& Context::info_log(const char* header) {
    std::ostream& l = ls_->log();

    for(int i = 0; i <= inline_depth_ - 1; i++) {
      l << "|";
    }

    l << "+ " << header << ": ";
    return l;
  }

}

#endif
<commit_msg>Move include to pickup version numbers<commit_after>#ifdef ENABLE_LLVM

#include "llvm/state.hpp"
#include "llvm/jit_context.hpp"
#include "llvm/jit_runtime.hpp"
#include "llvm/jit_memory_manager.hpp"
#include "llvm/passes.hpp"

#include "machine_code.hpp"

#if RBX_LLVM_API_VER >= 302
#include <llvm/DataLayout.h>
#else
#include <llvm/Target/TargetData.h>
#endif
#include <llvm/Transforms/Scalar.h>

using namespace llvm;

namespace autogen_types {
  void makeLLVMModuleContents(llvm::Module* module);
}

namespace rubinius {

  Context::Context(LLVMState* ls)
    : ls_(ls)
    , root_info_(0)
    , inlined_block_(false)
    , inline_depth_(0)
    , rds_(new jit::RuntimeDataHolder)
    , function_(0)
    , vm_(0)
    , out_args_(0)
    , counter_(0)
  {
    VoidTy = Type::getVoidTy(ctx_);

    Int1Ty = Type::getInt1Ty(ctx_);
    Int8Ty = Type::getInt8Ty(ctx_);
    Int16Ty = Type::getInt16Ty(ctx_);
    Int32Ty = Type::getInt32Ty(ctx_);
    Int64Ty = Type::getInt64Ty(ctx_);

#ifdef IS_X8664
    IntPtrTy = Int64Ty;
#else
    IntPtrTy = Int32Ty;
#endif

    VoidPtrTy = llvm::PointerType::getUnqual(Int8Ty);

    FloatTy = Type::getFloatTy(ctx_);
    DoubleTy = Type::getDoubleTy(ctx_);

    Int8PtrTy = llvm::PointerType::getUnqual(Int8Ty);

    Zero = llvm::ConstantInt::get(Int32Ty, 0);
    One = llvm::ConstantInt::get(Int32Ty, 1);

    module_ = new llvm::Module("rubinius", ctx_);

    autogen_types::makeLLVMModuleContents(module_);

    llvm::EngineBuilder factory(module_);

    factory.setAllocateGVsWithCode(false);
    memory_ = new jit::RubiniusRequestJITMemoryManager(ls->memory());
    factory.setJITMemoryManager(memory_);

#if RBX_LLVM_API_VER > 300
    llvm::TargetOptions opts;
    opts.NoFramePointerElim = true;
    opts.NoFramePointerElimNonLeaf = true;

    factory.setTargetOptions(opts);
#endif

    engine_ = factory.create();

    builder_ = new llvm::PassManagerBuilder();
    builder_->OptLevel = 2;
    passes_ = new llvm::FunctionPassManager(module_);

#if RBX_LLVM_API_VER >= 302
    module_->setDataLayout(engine_->getDataLayout()->getStringRepresentation());
    passes_->add(new llvm::DataLayout(*engine_->getDataLayout()));
#else
    module_->setDataLayout(engine_->getTargetData()->getStringRepresentation());
    passes_->add(new llvm::TargetData(*engine_->getTargetData()));
#endif

    builder_->populateFunctionPassManager(*passes_);

    // Eliminate unnecessary alloca.
    passes_->add(createPromoteMemoryToRegisterPass());
    // Do simple "peephole" optimizations and bit-twiddling optzns.
    passes_->add(createInstructionCombiningPass());
    // Reassociate expressions.
    passes_->add(createReassociatePass());
    // Eliminate Common SubExpressions.
    passes_->add(createGVNPass());
    passes_->add(createDeadStoreEliminationPass());

    passes_->add(createInstructionCombiningPass());

    // Simplify the control flow graph (deleting unreachable blocks, etc).
    passes_->add(createCFGSimplificationPass());

    passes_->add(create_rubinius_alias_analysis());
    passes_->add(createGVNPass());
    // passes_->add(createCFGSimplificationPass());
    passes_->add(createDeadStoreEliminationPass());
    // passes_->add(createVerifierPass());
    passes_->add(createScalarReplAggregatesPass());

    passes_->add(create_overflow_folding_pass());
    passes_->add(create_guard_eliminator_pass());

    passes_->add(createCFGSimplificationPass());
    passes_->add(createInstructionCombiningPass());
    passes_->add(createScalarReplAggregatesPass());
    passes_->add(createDeadStoreEliminationPass());
    passes_->add(createCFGSimplificationPass());
    passes_->add(createInstructionCombiningPass());
    passes_->doInitialization();

    ObjTy = ptr_type("Object");

    profiling_ = new GlobalVariable(
        *module_, Int1Ty, false,
        GlobalVariable::ExternalLinkage,
        0, "profiling_flag");

    metadata_id_ = ctx_.getMDKindID("rbx-classid");
  }

  Context::~Context() {
    delete builder_;
    delete passes_;
    delete engine_;
    // Memory is cleaned up by the engine
    memory_ = NULL;
  }

  void* Context::native_function() {
    void* addr = memory_->generatedFunction();
    memory_->resetGeneratedFunction();

    engine_->freeMachineCodeForFunction(function_);

    // Nuke the Function from the module
    function_->replaceAllUsesWith(UndefValue::get(function_->getType()));
    function_->removeFromParent();
    return addr;
  }

  llvm::Type* Context::ptr_type(std::string name) {
    std::string full_name = std::string("struct.rubinius::") + name;
    return llvm::PointerType::getUnqual(
        module_->getTypeByName(full_name));
  }

  llvm::Type* Context::type(std::string name) {
    std::string full_name = std::string("struct.rubinius::") + name;
    return module_->getTypeByName(full_name);
  }

  void Context::init_variables(llvm::IRBuilder<>& b) {
    counter_ = b.CreateAlloca(Int32Ty, 0, "counter_alloca");
    out_args_ = b.CreateAlloca(type("Arguments"), 0, "out_args");
  }

  void Context::add_runtime_data(jit::RuntimeData* rd) {
    rds_->add_runtime_data(rd);
  }

  std::ostream& Context::inline_log(const char* header) {
    std::ostream& l = ls_->log();

    for(int i = 0; i <= inline_depth_; i++) {
      l << "|";
    }

    l << " " << header << ": ";
    return l;
  }

  void Context::info(const char* msg) {
    if(!ls_->config().jit_inline_debug) return;

    std::ostream& l = ls_->log();

    for(int i = 0; i <= inline_depth_ - 1; i++) {
      l << "|";
    }

    l << "+ " << msg << "\n";
  }

  std::ostream& Context::info_log(const char* header) {
    std::ostream& l = ls_->log();

    for(int i = 0; i <= inline_depth_ - 1; i++) {
      l << "|";
    }

    l << "+ " << header << ": ";
    return l;
  }

}

#endif
<|endoftext|>


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

#include "providertx.h"
#include "specialtx.h"
#include "deterministicmns.h"

#include "hash.h"
#include "clientversion.h"
#include "streams.h"
#include "messagesigner.h"
#include "chainparams.h"
#include "validation.h"
#include "univalue.h"
#include "core_io.h"
#include "script/standard.h"
#include "base58.h"

template <typename ProTx>
static bool CheckService(const uint256& proTxHash, const ProTx& proTx, const CBlockIndex* pindexPrev, CValidationState& state)
{
    if (proTx.nProtocolVersion < MIN_PROTX_PROTO_VERSION || proTx.nProtocolVersion > MAX_PROTX_PROTO_VERSION)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-proto-version");

    if (!proTx.addr.IsValid())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");
    if (Params().NetworkIDString() != CBaseChainParams::REGTEST && !proTx.addr.IsRoutable())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");

    if (!proTx.addr.IsIPv4())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");

    if (pindexPrev) {
        auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
        if (mnList.HasUniqueProperty(proTx.addr) && mnList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTxHash) {
            return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
        }
    }

    return true;
}

template <typename ProTx>
static bool CheckInputsHashAndSig(const CTransaction &tx, const ProTx& proTx, const CKeyID &keyID, CValidationState& state)
{
    uint256 inputsHash = CalcTxInputsHash(tx);
    if (inputsHash != proTx.inputsHash)
        return state.DoS(100, false, REJECT_INVALID, "bad-protx-inputs-hash");

    std::string strError;
    if (!CHashSigner::VerifyHash(::SerializeHash(proTx), keyID, proTx.vchSig, strError))
        return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);

    return true;
}

bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
    AssertLockHeld(cs_main);

    CProRegTx ptx;
    if (!GetTxPayload(tx, ptx))
        return state.DoS(100, false, REJECT_INVALID, "bad-tx-payload");

    if (ptx.nVersion > CProRegTx::CURRENT_VERSION)
        return state.DoS(100, false, REJECT_INVALID, "bad-protx-version");

    if (ptx.nCollateralIndex >= tx.vout.size())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index");
    if (tx.vout[ptx.nCollateralIndex].nValue != 1000 * COIN)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
    if (ptx.keyIDOwner.IsNull() || ptx.keyIDOperator.IsNull() || ptx.keyIDVoting.IsNull())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-null");
    // we may support P2SH later, but restrict it for now (while in transitioning phase from old MN list to deterministic list)
    if (!ptx.scriptPayout.IsPayToPublicKeyHash())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee");

    // This is a temporary restriction that will be lifted later
    // It is required while we are transitioning from the old MN list to the deterministic list
    if (tx.vout[ptx.nCollateralIndex].scriptPubKey != ptx.scriptPayout)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-collateral");

    // It's allowed to set addr/protocolVersion to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
    // If any of both is set, it must be valid however
    if ((ptx.addr != CService() || ptx.nProtocolVersion != 0) && !CheckService(tx.GetHash(), ptx, pindexPrev, state))
        return false;

    if (ptx.nOperatorReward > 10000)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-reward");

    if (pindexPrev) {
        auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
        if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.keyIDOperator)) {
            return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-key");
        }

        if (!deterministicMNManager->IsDeterministicMNsSporkActive(pindexPrev->nHeight)) {
            if (ptx.keyIDOwner != ptx.keyIDOperator || ptx.keyIDOwner != ptx.keyIDVoting) {
                return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-not-same");
            }
        }
    }

    if (!CheckInputsHashAndSig(tx, ptx, ptx.keyIDOwner, state))
        return false;

    return true;
}

std::string CProRegTx::ToString() const
{
    CTxDestination dest;
    std::string payee = "unknown";
    if (ExtractDestination(scriptPayout, dest)) {
        payee = CBitcoinAddress(dest).ToString();
    }

    return strprintf("CProRegTx(nVersion=%d, nProtocolVersion=%d, nCollateralIndex=%d, addr=%s, nOperatorReward=%f, keyIDOwner=%s, keyIDOperator=%s, keyIDVoting=%s, scriptPayout=%s)",
        nVersion, nProtocolVersion, nCollateralIndex, addr.ToString(), (double)nOperatorReward / 100, keyIDOwner.ToString(), keyIDOperator.ToString(), keyIDVoting.ToString(), payee);
}

void CProRegTx::ToJson(UniValue& obj) const
{
    obj.clear();
    obj.setObject();
    obj.push_back(Pair("version", nVersion));
    obj.push_back(Pair("protocolVersion", nProtocolVersion));
    obj.push_back(Pair("collateralIndex", (int)nCollateralIndex));
    obj.push_back(Pair("service", addr.ToString(false)));
    obj.push_back(Pair("keyIDOwner", keyIDOwner.ToString()));
    obj.push_back(Pair("keyIDOperator", keyIDOperator.ToString()));
    obj.push_back(Pair("keyIDVoting", keyIDVoting.ToString()));

    CTxDestination dest;
    if (ExtractDestination(scriptPayout, dest)) {
        CBitcoinAddress bitcoinAddress(dest);
        obj.push_back(Pair("payoutAddress", bitcoinAddress.ToString()));
    }
    obj.push_back(Pair("operatorReward", (double)nOperatorReward / 100));

    obj.push_back(Pair("inputsHash", inputsHash.ToString()));
}

bool IsProTxCollateral(const CTransaction& tx, uint32_t n)
{
    return GetProTxCollateralIndex(tx) == n;
}

uint32_t GetProTxCollateralIndex(const CTransaction& tx)
{
    if (tx.nVersion < 3 || tx.nType != TRANSACTION_PROVIDER_REGISTER)
        return (uint32_t) - 1;
    CProRegTx proTx;
    if (!GetTxPayload(tx, proTx))
        assert(false);
    return proTx.nCollateralIndex;
}
<commit_msg>Split keyIDMasternode into keyIDOwner/keyIDOperator/keyIDVoting (#2248)<commit_after>// Copyright (c) 2018 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "providertx.h"
#include "specialtx.h"
#include "deterministicmns.h"

#include "hash.h"
#include "clientversion.h"
#include "streams.h"
#include "messagesigner.h"
#include "chainparams.h"
#include "validation.h"
#include "univalue.h"
#include "core_io.h"
#include "script/standard.h"
#include "base58.h"

template <typename ProTx>
static bool CheckService(const uint256& proTxHash, const ProTx& proTx, const CBlockIndex* pindexPrev, CValidationState& state)
{
    if (proTx.nProtocolVersion < MIN_PROTX_PROTO_VERSION || proTx.nProtocolVersion > MAX_PROTX_PROTO_VERSION)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-proto-version");

    if (!proTx.addr.IsValid())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");
    if (Params().NetworkIDString() != CBaseChainParams::REGTEST && !proTx.addr.IsRoutable())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");

    if (!proTx.addr.IsIPv4())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");

    if (pindexPrev) {
        auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
        if (mnList.HasUniqueProperty(proTx.addr) && mnList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTxHash) {
            return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
        }
    }

    return true;
}

template <typename ProTx>
static bool CheckInputsHashAndSig(const CTransaction &tx, const ProTx& proTx, const CKeyID &keyID, CValidationState& state)
{
    uint256 inputsHash = CalcTxInputsHash(tx);
    if (inputsHash != proTx.inputsHash)
        return state.DoS(100, false, REJECT_INVALID, "bad-protx-inputs-hash");

    std::string strError;
    if (!CHashSigner::VerifyHash(::SerializeHash(proTx), keyID, proTx.vchSig, strError))
        return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);

    return true;
}

bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
    AssertLockHeld(cs_main);

    CProRegTx ptx;
    if (!GetTxPayload(tx, ptx))
        return state.DoS(100, false, REJECT_INVALID, "bad-tx-payload");

    if (ptx.nVersion > CProRegTx::CURRENT_VERSION)
        return state.DoS(100, false, REJECT_INVALID, "bad-protx-version");

    if (ptx.nCollateralIndex >= tx.vout.size())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index");
    if (tx.vout[ptx.nCollateralIndex].nValue != 1000 * COIN)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
    if (ptx.keyIDOwner.IsNull() || ptx.keyIDOperator.IsNull() || ptx.keyIDVoting.IsNull())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-null");
    // we may support P2SH later, but restrict it for now (while in transitioning phase from old MN list to deterministic list)
    if (!ptx.scriptPayout.IsPayToPublicKeyHash())
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee");

    CTxDestination payoutDest;
    if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
        // should not happen as we checked script types before
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-dest");
    }
    // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
    if (payoutDest == CTxDestination(ptx.keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDOperator) || payoutDest == CTxDestination(ptx.keyIDVoting)) {
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
    }

    // This is a temporary restriction that will be lifted later
    // It is required while we are transitioning from the old MN list to the deterministic list
    if (tx.vout[ptx.nCollateralIndex].scriptPubKey != ptx.scriptPayout)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-collateral");

    // It's allowed to set addr/protocolVersion to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
    // If any of both is set, it must be valid however
    if ((ptx.addr != CService() || ptx.nProtocolVersion != 0) && !CheckService(tx.GetHash(), ptx, pindexPrev, state))
        return false;

    if (ptx.nOperatorReward > 10000)
        return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-reward");

    if (pindexPrev) {
        auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
        if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.keyIDOperator)) {
            return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-key");
        }

        if (!deterministicMNManager->IsDeterministicMNsSporkActive(pindexPrev->nHeight)) {
            if (ptx.keyIDOwner != ptx.keyIDOperator || ptx.keyIDOwner != ptx.keyIDVoting) {
                return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-not-same");
            }
        }
    }

    if (!CheckInputsHashAndSig(tx, ptx, ptx.keyIDOwner, state))
        return false;

    return true;
}

std::string CProRegTx::ToString() const
{
    CTxDestination dest;
    std::string payee = "unknown";
    if (ExtractDestination(scriptPayout, dest)) {
        payee = CBitcoinAddress(dest).ToString();
    }

    return strprintf("CProRegTx(nVersion=%d, nProtocolVersion=%d, nCollateralIndex=%d, addr=%s, nOperatorReward=%f, keyIDOwner=%s, keyIDOperator=%s, keyIDVoting=%s, scriptPayout=%s)",
        nVersion, nProtocolVersion, nCollateralIndex, addr.ToString(), (double)nOperatorReward / 100, keyIDOwner.ToString(), keyIDOperator.ToString(), keyIDVoting.ToString(), payee);
}

void CProRegTx::ToJson(UniValue& obj) const
{
    obj.clear();
    obj.setObject();
    obj.push_back(Pair("version", nVersion));
    obj.push_back(Pair("protocolVersion", nProtocolVersion));
    obj.push_back(Pair("collateralIndex", (int)nCollateralIndex));
    obj.push_back(Pair("service", addr.ToString(false)));
    obj.push_back(Pair("keyIDOwner", keyIDOwner.ToString()));
    obj.push_back(Pair("keyIDOperator", keyIDOperator.ToString()));
    obj.push_back(Pair("keyIDVoting", keyIDVoting.ToString()));

    CTxDestination dest;
    if (ExtractDestination(scriptPayout, dest)) {
        CBitcoinAddress bitcoinAddress(dest);
        obj.push_back(Pair("payoutAddress", bitcoinAddress.ToString()));
    }
    obj.push_back(Pair("operatorReward", (double)nOperatorReward / 100));

    obj.push_back(Pair("inputsHash", inputsHash.ToString()));
}

bool IsProTxCollateral(const CTransaction& tx, uint32_t n)
{
    return GetProTxCollateralIndex(tx) == n;
}

uint32_t GetProTxCollateralIndex(const CTransaction& tx)
{
    if (tx.nVersion < 3 || tx.nType != TRANSACTION_PROVIDER_REGISTER)
        return (uint32_t) - 1;
    CProRegTx proTx;
    if (!GetTxPayload(tx, proTx))
        assert(false);
    return proTx.nCollateralIndex;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 OWNER 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 "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("A~",  "Ares")
		, map_entry("AG",  "Ares")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AV", "Avicora")
		, map_entry("AX", "BitPump")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BC", "BitComet")
		, map_entry("BF", "Bitflu")
		, map_entry("BG", "BTG")
		, map_entry("BR", "BitRocket")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CD", "Enhanced CTorrent")
		, map_entry("CT", "CTorrent")
		, map_entry("DE", "Deluge Torrent")
		, map_entry("ES", "electric sheep")
		, map_entry("EB", "EBit")
		, map_entry("HL", "Halite")
		, map_entry("HN", "Hydranode")
		, map_entry("KT", "KTorrent")
		, map_entry("LK", "Linkage")
		, map_entry("LP", "lphant")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("ML", "MLDonkey")
		, map_entry("MO", "Mono Torrent")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("O",  "Osprey Permaseed")
		, map_entry("PD",  "Pando")
		, map_entry("QT", "Qt 4")
		, map_entry("R",  "Tribler")
		, map_entry("S",  "Shadow")
		, map_entry("S~",  "Shareaza (beta)")
		, map_entry("SB", "Swiftbit")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("SZ", "Shareaza")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TR", "Transmission")
		, map_entry("TS", "TorrentStorm")
		, map_entry("TT", "TuoTu")
		, map_entry("U",  "UPnP")
		, map_entry("UL", "uLeecher")
		, map_entry("UT", "MicroTorrent")
		, map_entry("XT", "XanTorrent")
		, map_entry("XX", "Xtorrent")
		, map_entry("ZT", "ZipTorrent")
		, map_entry("lt", "libTorrent (libtorrent.rakshasa.no/)")
		, map_entry("pX", "pHoeniX")
		, map_entry("qB", "qBittorrent")
	};

	bool compare_first_string(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.first[0] < rhs.first[0]
			|| ((lhs.first[0] == rhs.first[0]) && (lhs.first[1] < rhs.first[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, map_entry(f.name, ""), &compare_first_string);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_first_string(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->first))
			identity << i->second;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";
		if (find_string(PID, "OP")) return "Opera";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>cleanup and added another known peer-id<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 OWNER 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 "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta}"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "MicroTorrent"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "libTorrent (libtorrent.rakshasa.no/}"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";
		if (find_string(PID, "OP")) return "Opera";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>