<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: provider.cxx,v $
 *
 *  $Revision: 1.24 $
 *
 *  last change: $Author: obo $ $Date: 2008-03-25 15:21:52 $
 *
 *  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_xmlhelp.hxx"

/**************************************************************************
                                TODO
 **************************************************************************

 *************************************************************************/

#include <stdio.h>
#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _VOS_DIAGNOSE_HXX_
#include <vos/diagnose.hxx>
#endif
#ifndef _UCBHELPER_CONTENTIDENTIFIER_HXX
#include <ucbhelper/contentidentifier.hxx>
#endif
#ifndef _COM_SUN_STAR_FRAME_XCONFIGMANAGER_HPP_
#include <com/sun/star/frame/XConfigManager.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYSTATE_HPP_
#include <com/sun/star/beans/PropertyState.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XCONTAINER_HPP_
#include <com/sun/star/container/XContainer.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMEREPLACE_HPP_
#include <com/sun/star/container/XNameReplace.hpp>
#endif
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>

#include "databases.hxx"
#include "provider.hxx"
#include "content.hxx"
#include "databases.hxx"

using namespace com::sun::star;
using namespace chelp;

//=========================================================================
//=========================================================================
//
// ContentProvider Implementation.
//
//=========================================================================
//=========================================================================

ContentProvider::ContentProvider(
    const uno::Reference< lang::XMultiServiceFactory >& rSMgr )
    : ::ucbhelper::ContentProviderImplHelper( rSMgr ),
        isInitialized( false ),
        m_aScheme( rtl::OUString::createFromAscii( MYUCP_URL_SCHEME ) ),
        m_pDatabases( 0 )
{
}

//=========================================================================
// virtual
ContentProvider::~ContentProvider()
{
    delete m_pDatabases;
}

//=========================================================================
//
// XInterface methods.
//
//=========================================================================

XINTERFACE_IMPL_6( ContentProvider,
                   lang::XTypeProvider,
                   lang::XServiceInfo,
                   ucb::XContentProvider,
                   lang::XComponent,
                   lang::XEventListener, /* base of XContainerListener */
                   container::XContainerListener);

//=========================================================================
//
// XTypeProvider methods.
//
//=========================================================================

XTYPEPROVIDER_IMPL_5( ContentProvider,
                         lang::XTypeProvider,
                         lang::XServiceInfo,
                         ucb::XContentProvider,
                      lang::XComponent,
                      container::XContainerListener);

//=========================================================================
//
// XServiceInfo methods.
//
//=========================================================================

rtl::OUString SAL_CALL ContentProvider::getImplementationName()
    throw( uno::RuntimeException )
{
    return getImplementationName_Static();
}

rtl::OUString ContentProvider::getImplementationName_Static()
{
    return rtl::OUString::createFromAscii("CHelpContentProvider" );
}

sal_Bool SAL_CALL
ContentProvider::supportsService(const rtl::OUString& ServiceName )
    throw( uno::RuntimeException )
{
    uno::Sequence< rtl::OUString > aSNL = getSupportedServiceNames();
    const rtl::OUString* pArray = aSNL.getArray();
    for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
    {
        if( pArray[ i ] == ServiceName )
            return sal_True;
    }

    return sal_False;
}

uno::Sequence< rtl::OUString > SAL_CALL
ContentProvider::getSupportedServiceNames()
    throw( uno::RuntimeException )
{
    return getSupportedServiceNames_Static();
}

static uno::Reference< uno::XInterface > SAL_CALL
ContentProvider_CreateInstance(
         const uno::Reference< lang::XMultiServiceFactory> & rSMgr )
    throw( uno::Exception )
{
    lang::XServiceInfo * pX = static_cast< lang::XServiceInfo * >(
        new ContentProvider( rSMgr ) );
    return uno::Reference< uno::XInterface >::query( pX );
}

uno::Sequence< rtl::OUString >
ContentProvider::getSupportedServiceNames_Static()
{
    uno::Sequence< rtl::OUString > aSNS( 2 );
    aSNS.getArray()[ 0 ] =
        rtl::OUString::createFromAscii(
            MYUCP_CONTENT_PROVIDER_SERVICE_NAME1 );
    aSNS.getArray()[ 1 ] =
        rtl::OUString::createFromAscii(
            MYUCP_CONTENT_PROVIDER_SERVICE_NAME2 );

    return aSNS;
}

//=========================================================================
//
// Service factory implementation.
//
//=========================================================================

ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider );

//=========================================================================
//
// XContentProvider methods.
//
//=========================================================================

// virtual
uno::Reference< ucb::XContent > SAL_CALL
ContentProvider::queryContent(
        const uno::Reference< ucb::XContentIdentifier >& xCanonicId )
    throw( ucb::IllegalIdentifierException, uno::RuntimeException )
{
    if ( !xCanonicId->getContentProviderScheme()
             .equalsIgnoreAsciiCase( m_aScheme ) )
    {   // Wrong URL-scheme
        throw ucb::IllegalIdentifierException();
    }

    {
        osl::MutexGuard aGuard( m_aMutex );
        if( !isInitialized )
            init();
    }

    if( !m_pDatabases )
        throw uno::RuntimeException();

    rtl::OUString aOUString( m_pDatabases->getInstallPathAsURL() );
    rtl::OString aOString( aOUString.getStr(),
                           aOUString.getLength(),
                           RTL_TEXTENCODING_UTF8 );

    // Check, if a content with given id already exists...
    uno::Reference< ucb::XContent > xContent
        = queryExistingContent( xCanonicId ).get();
    if ( xContent.is() )
        return xContent;

    xContent = new Content( m_xSMgr, this, xCanonicId, m_pDatabases );

    // register new content
    registerNewContent( xContent );

    // Further checks

    if ( !xContent->getIdentifier().is() )
        throw ucb::IllegalIdentifierException();

    return xContent;
}

void SAL_CALL
ContentProvider::dispose()
    throw ( uno::RuntimeException)
{
    if(m_xContainer.is())
    {
        m_xContainer->removeContainerListener(this);
        m_xContainer.clear();
    }
}

void SAL_CALL
ContentProvider::elementReplaced(const container::ContainerEvent& Event)
    throw (uno::RuntimeException)
{
    if(!m_pDatabases)
        return;

    rtl::OUString accessor;
    Event.Accessor >>= accessor;
    if(accessor.compareToAscii("HelpStyleSheet"))
        return;

    rtl::OUString replacedElement,element;
    Event.ReplacedElement >>= replacedElement;
    Event.Element >>= element;

    if(replacedElement == element)
        return;

    m_pDatabases->changeCSS(element);
}

void ContentProvider::init()
{
    osl::MutexGuard aGuard( m_aMutex );

    isInitialized = true;
    uno::Reference< lang::XMultiServiceFactory > sProvider(
        getConfiguration() );
    uno::Reference< container::XHierarchicalNameAccess > xHierAccess(
        getHierAccess( sProvider,
                       "org.openoffice.Office.Common" ) );

    rtl::OUString instPath( getKey( xHierAccess,"Path/Current/Help" ) );
    if( ! instPath.getLength() )
        // try to determine path from default
        instPath = rtl::OUString::createFromAscii( "$(instpath)/help" );
    // replace anything like $(instpath);
    subst( instPath );

    rtl::OUString stylesheet( getKey( xHierAccess,"Help/HelpStyleSheet" ) );
    try
    {
        // now adding as configuration change listener for the stylesheet
        uno::Reference< container::XNameAccess> xAccess(
            xHierAccess, uno::UNO_QUERY );
        if( xAccess.is() )
        {
            uno::Any aAny =
                xAccess->getByName( rtl::OUString::createFromAscii( "Help" ) );
            aAny >>= m_xContainer;
            if( m_xContainer.is() )
                m_xContainer->addContainerListener( this );
        }
    }
    catch( uno::Exception const & )
    {
    }

    /**
     *  now determing
     *  productname,
     *  productversion,
     *  vendorname,
     *  vendorversion,
     *  vendorshort
     */

    xHierAccess = getHierAccess( sProvider, "org.openoffice.Setup" );
    rtl::OUString productname(
        getKey( xHierAccess,"Product/ooName" ) );

    rtl::OUString setupversion(
        getKey( xHierAccess,"Product/ooSetupVersion" ) );
    rtl::OUString setupextension(
        getKey( xHierAccess,"Product/ooSetupExtension") );
    rtl::OUString productversion(
        setupversion +
        rtl::OUString::createFromAscii( " " ) +
        setupextension );

    xHierAccess = getHierAccess( sProvider, "org.openoffice.Webtop.Common" );
    rtl::OUString vendorname(
        getKey( xHierAccess,"Product/ooName" ) );

    setupversion = rtl::OUString(
        getKey( xHierAccess,"Product/ooSetupVersion" ) );
    setupextension = rtl::OUString(
        getKey(  xHierAccess,"Product/ooSetupExtension") );
    rtl::OUString vendorversion(
        setupversion +
        rtl::OUString::createFromAscii( " " ) +
        setupextension );
    rtl::OUString vendorshort = vendorname;

    uno::Sequence< rtl::OUString > aImagesZipPaths( 2 );
    xHierAccess = getHierAccess( sProvider,  "org.openoffice.Office.Common" );

    rtl::OUString aPath( getKey( xHierAccess, "Path/Current/UserConfig" ) );
    subst( aPath );
    aImagesZipPaths[ 0 ] = aPath;

    aPath = getKey( xHierAccess, "Path/Current/Config" );
    subst( aPath );
    aImagesZipPaths[ 1 ] = aPath;

    uno::Reference< uno::XComponentContext > xContext;
    uno::Reference< beans::XPropertySet > xProps( m_xSMgr, uno::UNO_QUERY );
    OSL_ASSERT( xProps.is() );
    if (xProps.is())
    {
        xProps->getPropertyValue(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
        OSL_ASSERT( xContext.is() );
    }

    sal_Bool showBasic = getBooleanKey(xHierAccess,"Help/ShowBasic");
    m_pDatabases = new Databases( showBasic,
                                  instPath,
                                  aImagesZipPaths,
                                  productname,
                                  productversion,
                                  vendorname,
                                  vendorversion,
                                  vendorshort,
                                  stylesheet,
                                  xContext );
}

uno::Reference< lang::XMultiServiceFactory >
ContentProvider::getConfiguration() const
{
    uno::Reference< lang::XMultiServiceFactory > sProvider;
    if( m_xSMgr.is() )
    {
        uno::Any aAny;
        aAny <<= rtl::OUString::createFromAscii( "plugin" );
        beans::PropertyValue aProp(
            rtl::OUString::createFromAscii( "servertype" ),
            -1,
            aAny,
            beans::PropertyState_DIRECT_VALUE );

        uno::Sequence< uno::Any > seq(1);
        seq[0] <<= aProp;

        try
        {
            rtl::OUString sProviderService =
                rtl::OUString::createFromAscii(
                    "com.sun.star.configuration.ConfigurationProvider" );
            sProvider =
                uno::Reference< lang::XMultiServiceFactory >(
                    m_xSMgr->createInstanceWithArguments(
                        sProviderService,seq ),
                    uno::UNO_QUERY );
        }
        catch( const uno::Exception& )
        {
            OSL_ENSURE( sProvider.is(), "cant instantiate configuration" );
        }
    }

    return sProvider;
}

uno::Reference< container::XHierarchicalNameAccess >
ContentProvider::getHierAccess(
    const uno::Reference< lang::XMultiServiceFactory >& sProvider,
    const char* file ) const
{
    uno::Reference< container::XHierarchicalNameAccess > xHierAccess;

    if( sProvider.is() )
    {
        uno::Sequence< uno::Any > seq( 1 );
        rtl::OUString sReaderService(
            rtl::OUString::createFromAscii(
                "com.sun.star.configuration.ConfigurationAccess" ) );

        seq[ 0 ] <<= rtl::OUString::createFromAscii( file );

        try
        {
            xHierAccess =
                uno::Reference< container::XHierarchicalNameAccess >(
                    sProvider->createInstanceWithArguments(
                        sReaderService, seq ),
                    uno::UNO_QUERY );
        }
        catch( const uno::Exception& )
        {
        }
    }
    return xHierAccess;
}

rtl::OUString
ContentProvider::getKey(
    const uno::Reference< container::XHierarchicalNameAccess >& xHierAccess,
    const char* key ) const
{
    rtl::OUString instPath;
    if( xHierAccess.is() )
    {
        uno::Any aAny;
        try
        {
            aAny =
                xHierAccess->getByHierarchicalName(
                    rtl::OUString::createFromAscii( key ) );
        }
        catch( const container::NoSuchElementException& )
        {
        }
        aAny >>= instPath;
    }
    return instPath;
}

sal_Bool
ContentProvider::getBooleanKey(
    const uno::Reference< container::XHierarchicalNameAccess >& xHierAccess,
    const char* key ) const
{
  sal_Bool ret = sal_False;
  if( xHierAccess.is() )
  {
      uno::Any aAny;
      try
      {
          aAny =
            xHierAccess->getByHierarchicalName(
                rtl::OUString::createFromAscii( key ) );
      }
      catch( const container::NoSuchElementException& )
      {
      }
      aAny >>= ret;
  }
  return ret;
}

void ContentProvider::subst( rtl::OUString& instpath ) const
{
    uno::Reference< frame::XConfigManager > xCfgMgr;
    if( m_xSMgr.is() )
    {
        try
        {
            xCfgMgr =
                uno::Reference< frame::XConfigManager >(
                    m_xSMgr->createInstance(
                        rtl::OUString::createFromAscii(
                            "com.sun.star.config.SpecialConfigManager" ) ),
                    uno::UNO_QUERY );
        }
        catch( const uno::Exception&)
        {
            OSL_ENSURE( xCfgMgr.is(),
                        "cant instantiate the special config manager " );
        }
    }

    OSL_ENSURE( xCfgMgr.is(), "specialconfigmanager not found\n" );

    if( xCfgMgr.is() )
        instpath = xCfgMgr->substituteVariables( instpath );
}
<commit_msg>INTEGRATION: CWS changefileheader (1.24.2); FILE MERGED 2008/04/01 16:07:43 thb 1.24.2.3: #i85898# Stripping all external header guards 2008/04/01 13:02:58 thb 1.24.2.2: #i85898# Stripping all external header guards 2008/03/31 13:04:25 rt 1.24.2.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: provider.cxx,v $
 * $Revision: 1.25 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

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

/**************************************************************************
                                TODO
 **************************************************************************

 *************************************************************************/

#include <stdio.h>
#include <osl/file.hxx>
#ifndef _VOS_DIAGNOSE_HXX_
#include <vos/diagnose.hxx>
#endif
#include <ucbhelper/contentidentifier.hxx>
#include <com/sun/star/frame/XConfigManager.hpp>
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/PropertyState.hpp>
#include <com/sun/star/container/XContainer.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XNameReplace.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>

#include "databases.hxx"
#include "provider.hxx"
#include "content.hxx"
#include "databases.hxx"

using namespace com::sun::star;
using namespace chelp;

//=========================================================================
//=========================================================================
//
// ContentProvider Implementation.
//
//=========================================================================
//=========================================================================

ContentProvider::ContentProvider(
    const uno::Reference< lang::XMultiServiceFactory >& rSMgr )
    : ::ucbhelper::ContentProviderImplHelper( rSMgr ),
        isInitialized( false ),
        m_aScheme( rtl::OUString::createFromAscii( MYUCP_URL_SCHEME ) ),
        m_pDatabases( 0 )
{
}

//=========================================================================
// virtual
ContentProvider::~ContentProvider()
{
    delete m_pDatabases;
}

//=========================================================================
//
// XInterface methods.
//
//=========================================================================

XINTERFACE_IMPL_6( ContentProvider,
                   lang::XTypeProvider,
                   lang::XServiceInfo,
                   ucb::XContentProvider,
                   lang::XComponent,
                   lang::XEventListener, /* base of XContainerListener */
                   container::XContainerListener);

//=========================================================================
//
// XTypeProvider methods.
//
//=========================================================================

XTYPEPROVIDER_IMPL_5( ContentProvider,
                         lang::XTypeProvider,
                         lang::XServiceInfo,
                         ucb::XContentProvider,
                      lang::XComponent,
                      container::XContainerListener);

//=========================================================================
//
// XServiceInfo methods.
//
//=========================================================================

rtl::OUString SAL_CALL ContentProvider::getImplementationName()
    throw( uno::RuntimeException )
{
    return getImplementationName_Static();
}

rtl::OUString ContentProvider::getImplementationName_Static()
{
    return rtl::OUString::createFromAscii("CHelpContentProvider" );
}

sal_Bool SAL_CALL
ContentProvider::supportsService(const rtl::OUString& ServiceName )
    throw( uno::RuntimeException )
{
    uno::Sequence< rtl::OUString > aSNL = getSupportedServiceNames();
    const rtl::OUString* pArray = aSNL.getArray();
    for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
    {
        if( pArray[ i ] == ServiceName )
            return sal_True;
    }

    return sal_False;
}

uno::Sequence< rtl::OUString > SAL_CALL
ContentProvider::getSupportedServiceNames()
    throw( uno::RuntimeException )
{
    return getSupportedServiceNames_Static();
}

static uno::Reference< uno::XInterface > SAL_CALL
ContentProvider_CreateInstance(
         const uno::Reference< lang::XMultiServiceFactory> & rSMgr )
    throw( uno::Exception )
{
    lang::XServiceInfo * pX = static_cast< lang::XServiceInfo * >(
        new ContentProvider( rSMgr ) );
    return uno::Reference< uno::XInterface >::query( pX );
}

uno::Sequence< rtl::OUString >
ContentProvider::getSupportedServiceNames_Static()
{
    uno::Sequence< rtl::OUString > aSNS( 2 );
    aSNS.getArray()[ 0 ] =
        rtl::OUString::createFromAscii(
            MYUCP_CONTENT_PROVIDER_SERVICE_NAME1 );
    aSNS.getArray()[ 1 ] =
        rtl::OUString::createFromAscii(
            MYUCP_CONTENT_PROVIDER_SERVICE_NAME2 );

    return aSNS;
}

//=========================================================================
//
// Service factory implementation.
//
//=========================================================================

ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider );

//=========================================================================
//
// XContentProvider methods.
//
//=========================================================================

// virtual
uno::Reference< ucb::XContent > SAL_CALL
ContentProvider::queryContent(
        const uno::Reference< ucb::XContentIdentifier >& xCanonicId )
    throw( ucb::IllegalIdentifierException, uno::RuntimeException )
{
    if ( !xCanonicId->getContentProviderScheme()
             .equalsIgnoreAsciiCase( m_aScheme ) )
    {   // Wrong URL-scheme
        throw ucb::IllegalIdentifierException();
    }

    {
        osl::MutexGuard aGuard( m_aMutex );
        if( !isInitialized )
            init();
    }

    if( !m_pDatabases )
        throw uno::RuntimeException();

    rtl::OUString aOUString( m_pDatabases->getInstallPathAsURL() );
    rtl::OString aOString( aOUString.getStr(),
                           aOUString.getLength(),
                           RTL_TEXTENCODING_UTF8 );

    // Check, if a content with given id already exists...
    uno::Reference< ucb::XContent > xContent
        = queryExistingContent( xCanonicId ).get();
    if ( xContent.is() )
        return xContent;

    xContent = new Content( m_xSMgr, this, xCanonicId, m_pDatabases );

    // register new content
    registerNewContent( xContent );

    // Further checks

    if ( !xContent->getIdentifier().is() )
        throw ucb::IllegalIdentifierException();

    return xContent;
}

void SAL_CALL
ContentProvider::dispose()
    throw ( uno::RuntimeException)
{
    if(m_xContainer.is())
    {
        m_xContainer->removeContainerListener(this);
        m_xContainer.clear();
    }
}

void SAL_CALL
ContentProvider::elementReplaced(const container::ContainerEvent& Event)
    throw (uno::RuntimeException)
{
    if(!m_pDatabases)
        return;

    rtl::OUString accessor;
    Event.Accessor >>= accessor;
    if(accessor.compareToAscii("HelpStyleSheet"))
        return;

    rtl::OUString replacedElement,element;
    Event.ReplacedElement >>= replacedElement;
    Event.Element >>= element;

    if(replacedElement == element)
        return;

    m_pDatabases->changeCSS(element);
}

void ContentProvider::init()
{
    osl::MutexGuard aGuard( m_aMutex );

    isInitialized = true;
    uno::Reference< lang::XMultiServiceFactory > sProvider(
        getConfiguration() );
    uno::Reference< container::XHierarchicalNameAccess > xHierAccess(
        getHierAccess( sProvider,
                       "org.openoffice.Office.Common" ) );

    rtl::OUString instPath( getKey( xHierAccess,"Path/Current/Help" ) );
    if( ! instPath.getLength() )
        // try to determine path from default
        instPath = rtl::OUString::createFromAscii( "$(instpath)/help" );
    // replace anything like $(instpath);
    subst( instPath );

    rtl::OUString stylesheet( getKey( xHierAccess,"Help/HelpStyleSheet" ) );
    try
    {
        // now adding as configuration change listener for the stylesheet
        uno::Reference< container::XNameAccess> xAccess(
            xHierAccess, uno::UNO_QUERY );
        if( xAccess.is() )
        {
            uno::Any aAny =
                xAccess->getByName( rtl::OUString::createFromAscii( "Help" ) );
            aAny >>= m_xContainer;
            if( m_xContainer.is() )
                m_xContainer->addContainerListener( this );
        }
    }
    catch( uno::Exception const & )
    {
    }

    /**
     *  now determing
     *  productname,
     *  productversion,
     *  vendorname,
     *  vendorversion,
     *  vendorshort
     */

    xHierAccess = getHierAccess( sProvider, "org.openoffice.Setup" );
    rtl::OUString productname(
        getKey( xHierAccess,"Product/ooName" ) );

    rtl::OUString setupversion(
        getKey( xHierAccess,"Product/ooSetupVersion" ) );
    rtl::OUString setupextension(
        getKey( xHierAccess,"Product/ooSetupExtension") );
    rtl::OUString productversion(
        setupversion +
        rtl::OUString::createFromAscii( " " ) +
        setupextension );

    xHierAccess = getHierAccess( sProvider, "org.openoffice.Webtop.Common" );
    rtl::OUString vendorname(
        getKey( xHierAccess,"Product/ooName" ) );

    setupversion = rtl::OUString(
        getKey( xHierAccess,"Product/ooSetupVersion" ) );
    setupextension = rtl::OUString(
        getKey(  xHierAccess,"Product/ooSetupExtension") );
    rtl::OUString vendorversion(
        setupversion +
        rtl::OUString::createFromAscii( " " ) +
        setupextension );
    rtl::OUString vendorshort = vendorname;

    uno::Sequence< rtl::OUString > aImagesZipPaths( 2 );
    xHierAccess = getHierAccess( sProvider,  "org.openoffice.Office.Common" );

    rtl::OUString aPath( getKey( xHierAccess, "Path/Current/UserConfig" ) );
    subst( aPath );
    aImagesZipPaths[ 0 ] = aPath;

    aPath = getKey( xHierAccess, "Path/Current/Config" );
    subst( aPath );
    aImagesZipPaths[ 1 ] = aPath;

    uno::Reference< uno::XComponentContext > xContext;
    uno::Reference< beans::XPropertySet > xProps( m_xSMgr, uno::UNO_QUERY );
    OSL_ASSERT( xProps.is() );
    if (xProps.is())
    {
        xProps->getPropertyValue(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
        OSL_ASSERT( xContext.is() );
    }

    sal_Bool showBasic = getBooleanKey(xHierAccess,"Help/ShowBasic");
    m_pDatabases = new Databases( showBasic,
                                  instPath,
                                  aImagesZipPaths,
                                  productname,
                                  productversion,
                                  vendorname,
                                  vendorversion,
                                  vendorshort,
                                  stylesheet,
                                  xContext );
}

uno::Reference< lang::XMultiServiceFactory >
ContentProvider::getConfiguration() const
{
    uno::Reference< lang::XMultiServiceFactory > sProvider;
    if( m_xSMgr.is() )
    {
        uno::Any aAny;
        aAny <<= rtl::OUString::createFromAscii( "plugin" );
        beans::PropertyValue aProp(
            rtl::OUString::createFromAscii( "servertype" ),
            -1,
            aAny,
            beans::PropertyState_DIRECT_VALUE );

        uno::Sequence< uno::Any > seq(1);
        seq[0] <<= aProp;

        try
        {
            rtl::OUString sProviderService =
                rtl::OUString::createFromAscii(
                    "com.sun.star.configuration.ConfigurationProvider" );
            sProvider =
                uno::Reference< lang::XMultiServiceFactory >(
                    m_xSMgr->createInstanceWithArguments(
                        sProviderService,seq ),
                    uno::UNO_QUERY );
        }
        catch( const uno::Exception& )
        {
            OSL_ENSURE( sProvider.is(), "cant instantiate configuration" );
        }
    }

    return sProvider;
}

uno::Reference< container::XHierarchicalNameAccess >
ContentProvider::getHierAccess(
    const uno::Reference< lang::XMultiServiceFactory >& sProvider,
    const char* file ) const
{
    uno::Reference< container::XHierarchicalNameAccess > xHierAccess;

    if( sProvider.is() )
    {
        uno::Sequence< uno::Any > seq( 1 );
        rtl::OUString sReaderService(
            rtl::OUString::createFromAscii(
                "com.sun.star.configuration.ConfigurationAccess" ) );

        seq[ 0 ] <<= rtl::OUString::createFromAscii( file );

        try
        {
            xHierAccess =
                uno::Reference< container::XHierarchicalNameAccess >(
                    sProvider->createInstanceWithArguments(
                        sReaderService, seq ),
                    uno::UNO_QUERY );
        }
        catch( const uno::Exception& )
        {
        }
    }
    return xHierAccess;
}

rtl::OUString
ContentProvider::getKey(
    const uno::Reference< container::XHierarchicalNameAccess >& xHierAccess,
    const char* key ) const
{
    rtl::OUString instPath;
    if( xHierAccess.is() )
    {
        uno::Any aAny;
        try
        {
            aAny =
                xHierAccess->getByHierarchicalName(
                    rtl::OUString::createFromAscii( key ) );
        }
        catch( const container::NoSuchElementException& )
        {
        }
        aAny >>= instPath;
    }
    return instPath;
}

sal_Bool
ContentProvider::getBooleanKey(
    const uno::Reference< container::XHierarchicalNameAccess >& xHierAccess,
    const char* key ) const
{
  sal_Bool ret = sal_False;
  if( xHierAccess.is() )
  {
      uno::Any aAny;
      try
      {
          aAny =
            xHierAccess->getByHierarchicalName(
                rtl::OUString::createFromAscii( key ) );
      }
      catch( const container::NoSuchElementException& )
      {
      }
      aAny >>= ret;
  }
  return ret;
}

void ContentProvider::subst( rtl::OUString& instpath ) const
{
    uno::Reference< frame::XConfigManager > xCfgMgr;
    if( m_xSMgr.is() )
    {
        try
        {
            xCfgMgr =
                uno::Reference< frame::XConfigManager >(
                    m_xSMgr->createInstance(
                        rtl::OUString::createFromAscii(
                            "com.sun.star.config.SpecialConfigManager" ) ),
                    uno::UNO_QUERY );
        }
        catch( const uno::Exception&)
        {
            OSL_ENSURE( xCfgMgr.is(),
                        "cant instantiate the special config manager " );
        }
    }

    OSL_ENSURE( xCfgMgr.is(), "specialconfigmanager not found\n" );

    if( xCfgMgr.is() )
        instpath = xCfgMgr->substituteVariables( instpath );
}
<|endoftext|>


<commit_before>#include "pink/src/worker_thread.h"

#include "pink/include/pink_conn.h"
#include "pink/src/pink_item.h"
#include "pink/src/pink_epoll.h"
#include "pink/src/csapp.h"

namespace pink {

WorkerThread::WorkerThread(ConnFactory *conn_factory, ServerThread* server_thread,
                           int cron_interval)
      : server_thread_(server_thread),
        conn_factory_(conn_factory),
        cron_interval_(cron_interval),
        keepalive_timeout_(kDefaultKeepAliveTime) {
  /*
   * install the protobuf handler here
   */
  pink_epoll_ = new PinkEpoll();
  int fds[2];
  if (pipe(fds)) {
    exit(-1);
  }
  notify_receive_fd_ = fds[0];
  notify_send_fd_ = fds[1];
  pink_epoll_->PinkAddEvent(notify_receive_fd_, EPOLLIN | EPOLLERR | EPOLLHUP);
}

WorkerThread::~WorkerThread() {
  delete(pink_epoll_);
}

int WorkerThread::conn_num() const {
  slash::ReadLock l(&rwlock_);
  return conns_.size();
}

std::vector<ServerThread::ConnInfo> WorkerThread::conns_info() const {
  std::vector<ServerThread::ConnInfo> result;
  slash::ReadLock l(&rwlock_);
  for (auto& conn : conns_) {
    result.push_back({
                      conn.first,
                      conn.second->ip_port(),
                      conn.second->last_interaction()
                     });
  }
  return result;
}

PinkConn* WorkerThread::MoveConnOut(int fd) {
  slash::WriteLock l(&rwlock_);
  PinkConn* conn = nullptr;
  auto iter = conns_.find(fd);
  if (iter != conns_.end()) {
    int fd = iter->first;
    conn = iter->second;
    pink_epoll_->PinkDelEvent(fd);
    conns_.erase(iter);
  }
  return conn;
}

void *WorkerThread::ThreadMain() {
  int nfds;
  PinkFiredEvent *pfe = NULL;
  char bb[1];
  PinkItem ti;
  PinkConn *in_conn = NULL;

  struct timeval when;
  gettimeofday(&when, NULL);
  struct timeval now = when;

  when.tv_sec += (cron_interval_ / 1000);
  when.tv_usec += ((cron_interval_ % 1000 ) * 1000);
  int timeout = cron_interval_;
  if (timeout <= 0) {
    timeout = PINK_CRON_INTERVAL;
  }

  while (!should_stop()) {

    if (cron_interval_ > 0) {
      gettimeofday(&now, NULL);
      if (when.tv_sec > now.tv_sec || (when.tv_sec == now.tv_sec && when.tv_usec > now.tv_usec)) {
        timeout = (when.tv_sec - now.tv_sec) * 1000 + (when.tv_usec - now.tv_usec) / 1000;
      } else {
        DoCronTask();
        when.tv_sec = now.tv_sec + (cron_interval_ / 1000);
        when.tv_usec = now.tv_usec + ((cron_interval_ % 1000 ) * 1000);
        timeout = cron_interval_;
      }
    }

    nfds = pink_epoll_->PinkPoll(timeout);

    for (int i = 0; i < nfds; i++) {
      pfe = (pink_epoll_->firedevent()) + i;
      if (pfe->fd == notify_receive_fd_) {
        if (pfe->mask & EPOLLIN) {
          read(notify_receive_fd_, bb, 1);
          {
            slash::MutexLock l(&mutex_);
            ti = conn_queue_.front();
            conn_queue_.pop();
          }
          PinkConn *tc = conn_factory_->NewPinkConn(ti.fd(), ti.ip_port(),
                                                    server_thread_, private_data_);
          if (!tc || !tc->SetNonblock()) {
            delete tc;
            continue;
          }

#ifdef __ENABLE_SSL
          // Create SSL failed
          if (server_thread_->security() &&
              !tc->CreateSSL(server_thread_->ssl_ctx())) {
            CloseFd(tc);
            delete tc;
            continue;
          }
#endif

          {
          slash::WriteLock l(&rwlock_);
          conns_[ti.fd()] = tc;
          }
          pink_epoll_->PinkAddEvent(ti.fd(), EPOLLIN);
        } else {
          continue;
        }
      } else {
        in_conn = NULL;
        int should_close = 0;
        if (pfe == NULL) {
          continue;
        }
        std::map<int, PinkConn *>::iterator iter = conns_.find(pfe->fd);
        if (iter == conns_.end()) {
          pink_epoll_->PinkDelEvent(pfe->fd);
          continue;
        }

        in_conn = iter->second;
        if (pfe->mask & EPOLLIN) {
          ReadStatus getRes = in_conn->GetRequest();
          in_conn->set_last_interaction(now);
          if (getRes != kReadAll && getRes != kReadHalf) {
            // kReadError kReadClose kFullError kParseError
            should_close = 1;
          } else if (in_conn->is_reply()) {
            pink_epoll_->PinkModEvent(pfe->fd, EPOLLIN, EPOLLOUT);
          } else {
            continue;
          }
        }
        if (pfe->mask & EPOLLOUT) {
          WriteStatus write_status = in_conn->SendReply();
          if (write_status == kWriteAll) {
            in_conn->set_is_reply(false);
            pink_epoll_->PinkModEvent(pfe->fd, 0, EPOLLIN);
          } else if (write_status == kWriteHalf) {
            continue;
          } else if (write_status == kWriteError) {
            should_close = 1;
          }
        }
        if ((pfe->mask & EPOLLERR) || (pfe->mask & EPOLLHUP) || should_close) {
          {
            slash::WriteLock l(&rwlock_);
            pink_epoll_->PinkDelEvent(pfe->fd);
            CloseFd(in_conn);
            delete(in_conn);
            in_conn = NULL;

            conns_.erase(pfe->fd);
          }
        }
      } // connection event
    } // for (int i = 0; i < nfds; i++)
  } // while (!should_stop())

  Cleanup();
  return NULL;
}

void WorkerThread::DoCronTask() {
  struct timeval now;
  gettimeofday(&now, NULL);
  slash::WriteLock l(&rwlock_);

  // Check whether close all connection
  slash::MutexLock kl(&killer_mutex_);
  if (deleting_conn_ipport_.count(kKillAllConnsTask)) {
    for (auto& conn : conns_) {
      CloseFd(conn.second);
      delete conn.second;
    }
    conns_.clear();
    deleting_conn_ipport_.clear();
    return;
  }

  std::map<int, PinkConn*>::iterator iter = conns_.begin();
  while (iter != conns_.end()) {
    // Check connection should be closed
    if (deleting_conn_ipport_.count(iter->second->ip_port())) {
      CloseFd(iter->second);
      deleting_conn_ipport_.erase(iter->second->ip_port());
      delete iter->second;
      iter = conns_.erase(iter);
      continue;
    }

    // Check keepalive timeout connection
    if (keepalive_timeout_ > 0 &&
        now.tv_sec - iter->second->last_interaction().tv_sec > keepalive_timeout_) {
      CloseFd(iter->second);
      server_thread_->handle_->FdTimeoutHandle(iter->first, iter->second->ip_port());
      delete iter->second;
      iter = conns_.erase(iter);
      continue;
    }
    ++iter;
  }
}

bool WorkerThread::TryKillConn(const std::string& ip_port) {
  bool find = false;
  if (ip_port != kKillAllConnsTask) {
    slash::ReadLock l(&rwlock_);
    for (auto& iter : conns_) {
      if (iter.second->ip_port() == ip_port) {
        find = true;
        break;
      }
    }
  }
  if (find || ip_port == kKillAllConnsTask) {
    slash::MutexLock l(&killer_mutex_);
    deleting_conn_ipport_.insert(ip_port);
    return true;
  }
  return false;
}

void WorkerThread::CloseFd(PinkConn* conn) {
  close(conn->fd());
  server_thread_->handle_->FdClosedHandle(conn->fd(), conn->ip_port());
}

void WorkerThread::Cleanup() {
  slash::WriteLock l(&rwlock_);
  for (auto& iter : conns_) {
    CloseFd(iter.second);
    delete iter.second;
  }
  conns_.clear();
}

};  // namespace pink
<commit_msg>Bugfix: update action time while send reply<commit_after>#include "pink/src/worker_thread.h"

#include "pink/include/pink_conn.h"
#include "pink/src/pink_item.h"
#include "pink/src/pink_epoll.h"
#include "pink/src/csapp.h"

namespace pink {

WorkerThread::WorkerThread(ConnFactory *conn_factory, ServerThread* server_thread,
                           int cron_interval)
      : server_thread_(server_thread),
        conn_factory_(conn_factory),
        cron_interval_(cron_interval),
        keepalive_timeout_(kDefaultKeepAliveTime) {
  /*
   * install the protobuf handler here
   */
  pink_epoll_ = new PinkEpoll();
  int fds[2];
  if (pipe(fds)) {
    exit(-1);
  }
  notify_receive_fd_ = fds[0];
  notify_send_fd_ = fds[1];
  pink_epoll_->PinkAddEvent(notify_receive_fd_, EPOLLIN | EPOLLERR | EPOLLHUP);
}

WorkerThread::~WorkerThread() {
  delete(pink_epoll_);
}

int WorkerThread::conn_num() const {
  slash::ReadLock l(&rwlock_);
  return conns_.size();
}

std::vector<ServerThread::ConnInfo> WorkerThread::conns_info() const {
  std::vector<ServerThread::ConnInfo> result;
  slash::ReadLock l(&rwlock_);
  for (auto& conn : conns_) {
    result.push_back({
                      conn.first,
                      conn.second->ip_port(),
                      conn.second->last_interaction()
                     });
  }
  return result;
}

PinkConn* WorkerThread::MoveConnOut(int fd) {
  slash::WriteLock l(&rwlock_);
  PinkConn* conn = nullptr;
  auto iter = conns_.find(fd);
  if (iter != conns_.end()) {
    int fd = iter->first;
    conn = iter->second;
    pink_epoll_->PinkDelEvent(fd);
    conns_.erase(iter);
  }
  return conn;
}

void *WorkerThread::ThreadMain() {
  int nfds;
  PinkFiredEvent *pfe = NULL;
  char bb[1];
  PinkItem ti;
  PinkConn *in_conn = NULL;

  struct timeval when;
  gettimeofday(&when, NULL);
  struct timeval now = when;

  when.tv_sec += (cron_interval_ / 1000);
  when.tv_usec += ((cron_interval_ % 1000 ) * 1000);
  int timeout = cron_interval_;
  if (timeout <= 0) {
    timeout = PINK_CRON_INTERVAL;
  }

  while (!should_stop()) {

    if (cron_interval_ > 0) {
      gettimeofday(&now, NULL);
      if (when.tv_sec > now.tv_sec || (when.tv_sec == now.tv_sec && when.tv_usec > now.tv_usec)) {
        timeout = (when.tv_sec - now.tv_sec) * 1000 + (when.tv_usec - now.tv_usec) / 1000;
      } else {
        DoCronTask();
        when.tv_sec = now.tv_sec + (cron_interval_ / 1000);
        when.tv_usec = now.tv_usec + ((cron_interval_ % 1000 ) * 1000);
        timeout = cron_interval_;
      }
    }

    nfds = pink_epoll_->PinkPoll(timeout);

    for (int i = 0; i < nfds; i++) {
      pfe = (pink_epoll_->firedevent()) + i;
      if (pfe->fd == notify_receive_fd_) {
        if (pfe->mask & EPOLLIN) {
          read(notify_receive_fd_, bb, 1);
          {
            slash::MutexLock l(&mutex_);
            ti = conn_queue_.front();
            conn_queue_.pop();
          }
          PinkConn *tc = conn_factory_->NewPinkConn(ti.fd(), ti.ip_port(),
                                                    server_thread_, private_data_);
          if (!tc || !tc->SetNonblock()) {
            delete tc;
            continue;
          }

#ifdef __ENABLE_SSL
          // Create SSL failed
          if (server_thread_->security() &&
              !tc->CreateSSL(server_thread_->ssl_ctx())) {
            CloseFd(tc);
            delete tc;
            continue;
          }
#endif

          {
          slash::WriteLock l(&rwlock_);
          conns_[ti.fd()] = tc;
          }
          pink_epoll_->PinkAddEvent(ti.fd(), EPOLLIN);
        } else {
          continue;
        }
      } else {
        in_conn = NULL;
        int should_close = 0;
        if (pfe == NULL) {
          continue;
        }
        std::map<int, PinkConn *>::iterator iter = conns_.find(pfe->fd);
        if (iter == conns_.end()) {
          pink_epoll_->PinkDelEvent(pfe->fd);
          continue;
        }

        in_conn = iter->second;
        if (pfe->mask & EPOLLIN) {
          ReadStatus getRes = in_conn->GetRequest();
          in_conn->set_last_interaction(now);
          if (getRes != kReadAll && getRes != kReadHalf) {
            // kReadError kReadClose kFullError kParseError
            should_close = 1;
          } else if (in_conn->is_reply()) {
            pink_epoll_->PinkModEvent(pfe->fd, EPOLLIN, EPOLLOUT);
          } else {
            continue;
          }
        }
        if (pfe->mask & EPOLLOUT) {
          WriteStatus write_status = in_conn->SendReply();
          in_conn->set_last_interaction(now);
          if (write_status == kWriteAll) {
            in_conn->set_is_reply(false);
            pink_epoll_->PinkModEvent(pfe->fd, 0, EPOLLIN);
          } else if (write_status == kWriteHalf) {
            continue;
          } else if (write_status == kWriteError) {
            should_close = 1;
          }
        }
        if ((pfe->mask & EPOLLERR) || (pfe->mask & EPOLLHUP) || should_close) {
          {
            slash::WriteLock l(&rwlock_);
            pink_epoll_->PinkDelEvent(pfe->fd);
            CloseFd(in_conn);
            delete(in_conn);
            in_conn = NULL;

            conns_.erase(pfe->fd);
          }
        }
      } // connection event
    } // for (int i = 0; i < nfds; i++)
  } // while (!should_stop())

  Cleanup();
  return NULL;
}

void WorkerThread::DoCronTask() {
  struct timeval now;
  gettimeofday(&now, NULL);
  slash::WriteLock l(&rwlock_);

  // Check whether close all connection
  slash::MutexLock kl(&killer_mutex_);
  if (deleting_conn_ipport_.count(kKillAllConnsTask)) {
    for (auto& conn : conns_) {
      CloseFd(conn.second);
      delete conn.second;
    }
    conns_.clear();
    deleting_conn_ipport_.clear();
    return;
  }

  std::map<int, PinkConn*>::iterator iter = conns_.begin();
  while (iter != conns_.end()) {
    // Check connection should be closed
    if (deleting_conn_ipport_.count(iter->second->ip_port())) {
      CloseFd(iter->second);
      deleting_conn_ipport_.erase(iter->second->ip_port());
      delete iter->second;
      iter = conns_.erase(iter);
      continue;
    }

    // Check keepalive timeout connection
    if (keepalive_timeout_ > 0 &&
        now.tv_sec - iter->second->last_interaction().tv_sec > keepalive_timeout_) {
      CloseFd(iter->second);
      server_thread_->handle_->FdTimeoutHandle(iter->first, iter->second->ip_port());
      delete iter->second;
      iter = conns_.erase(iter);
      continue;
    }
    ++iter;
  }
}

bool WorkerThread::TryKillConn(const std::string& ip_port) {
  bool find = false;
  if (ip_port != kKillAllConnsTask) {
    slash::ReadLock l(&rwlock_);
    for (auto& iter : conns_) {
      if (iter.second->ip_port() == ip_port) {
        find = true;
        break;
      }
    }
  }
  if (find || ip_port == kKillAllConnsTask) {
    slash::MutexLock l(&killer_mutex_);
    deleting_conn_ipport_.insert(ip_port);
    return true;
  }
  return false;
}

void WorkerThread::CloseFd(PinkConn* conn) {
  close(conn->fd());
  server_thread_->handle_->FdClosedHandle(conn->fd(), conn->ip_port());
}

void WorkerThread::Cleanup() {
  slash::WriteLock l(&rwlock_);
  for (auto& iter : conns_) {
    CloseFd(iter.second);
    delete iter.second;
  }
  conns_.clear();
}

};  // namespace pink
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2011, Willow Garage, Inc.
 *
 *  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 Willow Garage, Inc. 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 <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <pcl/common/time.h> //fps calculations
#include <pcl/io/openni_grabber.h>
#include <pcl/io/openni_camera/openni_driver.h>
#include <pcl/console/parse.h>
#include <vtkImageViewer.h>
#include <vtkImageImport.h>
#include <vtkJPEGWriter.h>
#include <vtkBMPWriter.h>
#include <vtkPNGWriter.h>
#include <vtkTIFFWriter.h>
#include <vector>
#include <string>

#include <pcl/visualization/pcl_visualizer.h>

#define SHOW_FPS 1
#if SHOW_FPS
#define FPS_CALC(_WHAT_) \
do \
{ \
    static unsigned count = 0;\
    static double last = pcl::getTime ();\
    double now = pcl::getTime (); \
    ++count; \
    if (now - last >= 1.0) \
    { \
      std::cout << "Average framerate("<< _WHAT_ << "): " << double(count)/double(now - last) << " Hz" <<  std::endl; \
      count = 0; \
      last = now; \
    } \
}while(false)
#else
#define FPS_CALC(_WHAT_) \
do \
{ \
}while(false)
#endif

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class SimpleOpenNIViewer
{
  public:
    SimpleOpenNIViewer (pcl::OpenNIGrabber& grabber)
      : grabber_ (grabber),
        importer_ (vtkSmartPointer<vtkImageImport>::New ()),
        depth_importer_ (vtkSmartPointer<vtkImageImport>::New ()),
        writer_ (vtkSmartPointer<vtkTIFFWriter>::New ())
    {
      importer_->SetNumberOfScalarComponents (3);
      importer_->SetDataScalarTypeToUnsignedChar ();
      depth_importer_->SetNumberOfScalarComponents (1);
      depth_importer_->SetDataScalarTypeToUnsignedShort ();
      writer_->SetCompressionToPackBits ();
    }

    void
    image_callback (const boost::shared_ptr<openni_wrapper::Image> &image,
                    const boost::shared_ptr<openni_wrapper::DepthImage> &depth_image, float constant)
    {
      FPS_CALC ("image callback");
      boost::mutex::scoped_lock lock (image_mutex_);
      image_ = image;
      depth_image_ = depth_image;
    }

    void
    run ()
    {
      boost::function<void (const boost::shared_ptr<openni_wrapper::Image>&, const boost::shared_ptr<openni_wrapper::DepthImage>&, float) > image_cb = boost::bind (&SimpleOpenNIViewer::image_callback, this, _1, _2, _3);
      boost::signals2::connection image_connection = grabber_.registerCallback (image_cb);

      grabber_.start ();

      unsigned char* rgb_data = 0;
      unsigned rgb_data_size = 0;
      void* data;

      while (true)
      {
        boost::mutex::scoped_lock lock (image_mutex_);

        std::string time = boost::posix_time::to_iso_string (boost::posix_time::microsec_clock::local_time ());
        if (image_)
        {
          FPS_CALC ("writer callback");
          boost::shared_ptr<openni_wrapper::Image> image;
          image.swap (image_);

          if (image->getEncoding() == openni_wrapper::Image::RGB)
          {
            data = (void*)image->getMetaData ().Data ();
            importer_->SetWholeExtent (0, image->getWidth () - 1, 0, image->getHeight () - 1, 0, 0);
            importer_->SetDataExtentToWholeExtent ();
          }
          else
          {
            if (rgb_data_size < image->getWidth () * image->getHeight ())
            {
              rgb_data_size = image->getWidth () * image->getHeight ();
              rgb_data = new unsigned char [rgb_data_size * 3];
              importer_->SetWholeExtent (0, image->getWidth () - 1, 0, image->getHeight () - 1, 0, 0);
              importer_->SetDataExtentToWholeExtent ();
            }
            image->fillRGB (image->getWidth (), image->getHeight (), rgb_data);
            data = (void*)rgb_data;
          }

          std::stringstream ss;
          ss << "frame_" + time + "_rgb.tiff";
          importer_->SetImportVoidPointer (data, 1);
          importer_->Update ();
          writer_->SetFileName (ss.str ().c_str ());
          writer_->SetInputConnection (importer_->GetOutputPort ());
          writer_->Write ();
        }

        if (depth_image_)
        {
          boost::shared_ptr<openni_wrapper::DepthImage> depth_image;
          depth_image.swap (depth_image_);

          std::stringstream ss;
          ss << "frame_" + time + "_depth.tiff";

          depth_importer_->SetWholeExtent (0, depth_image->getWidth () - 1, 0, depth_image->getHeight () - 1, 0, 0);
          depth_importer_->SetDataExtentToWholeExtent ();
          depth_importer_->SetImportVoidPointer ((void*)depth_image->getDepthMetaData ().Data (), 1);
          depth_importer_->Update ();
          writer_->SetFileName (ss.str ().c_str ());
          writer_->SetInputConnection (depth_importer_->GetOutputPort ());
          writer_->Write ();
        }
      }

      grabber_.stop ();

      image_connection.disconnect ();

      if (rgb_data)
        delete[] rgb_data;
    }

    pcl::OpenNIGrabber& grabber_;
    boost::mutex image_mutex_;
    boost::shared_ptr<openni_wrapper::Image> image_;
    boost::shared_ptr<openni_wrapper::DepthImage> depth_image_;
    vtkSmartPointer<vtkImageImport> importer_, depth_importer_;
    vtkSmartPointer<vtkTIFFWriter> writer_;
};

void
usage (char ** argv)
{
  cout << "usage: " << argv[0] << " [((<device_id> | <path-to-oni-file>) [-imagemode <mode>] | -l [<device_id>]| -h | --help)]" << endl;
  cout << argv[0] << " -h | --help : shows this help" << endl;
  cout << argv[0] << " -l : list all available devices" << endl;
  cout << argv[0] << " -l <device-id> : list all available modes for specified device" << endl;

  cout << "                 device_id may be #1, #2, ... for the first, second etc device in the list"
#ifndef _WIN32
       << " or" << endl
       << "                 bus@address for the device connected to a specific usb-bus / address combination or" << endl
       << "                 <serial-number>"
#endif
       << endl;
  cout << endl;
  cout << "examples:" << endl;
  cout << argv[0] << " \"#1\"" << endl;
  cout << "    uses the first device." << endl;
  cout << argv[0] << " \"./temp/test.oni\"" << endl;
  cout << "    uses the oni-player device to play back oni file given by path." << endl;
  cout << argv[0] << " -l" << endl;
  cout << "    lists all available devices." << endl;
  cout << argv[0] << " -l \"#2\"" << endl;
  cout << "    lists all available modes for the second device" << endl;
#ifndef _WIN32
  cout << argv[0] << " A00361800903049A" << endl;
  cout << "    uses the device with the serial number \'A00361800903049A\'." << endl;
  cout << argv[0] << " 1@16" << endl;
  cout << "    uses the device on address 16 at USB bus 1." << endl;
#endif
  return;
}

int
main(int argc, char ** argv)
{
  std::string device_id ("");
  pcl::OpenNIGrabber::Mode image_mode = pcl::OpenNIGrabber::OpenNI_Default_Mode;

  if (argc >= 2)
  {
    device_id = argv[1];
    if (device_id == "--help" || device_id == "-h")
    {
      usage(argv);
      return 0;
    }
    else if (device_id == "-l")
    {
      if (argc >= 3)
      {
        pcl::OpenNIGrabber grabber (argv[2]);
        boost::shared_ptr<openni_wrapper::OpenNIDevice> device = grabber.getDevice ();
        std::vector<std::pair<int, XnMapOutputMode> > modes;

        if (device->hasImageStream ())
        {
          cout << endl << "Supported image modes for device: " << device->getVendorName () << " , " << device->getProductName () << endl;
          modes = grabber.getAvailableImageModes ();
          for (std::vector<std::pair<int, XnMapOutputMode> >::const_iterator it = modes.begin (); it != modes.end (); ++it)
          {
            cout << it->first << " = " << it->second.nXRes << " x " << it->second.nYRes << " @ " << it->second.nFPS << endl;
          }
        }
      }
      else
      {
        openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
        if (driver.getNumberDevices () > 0)
        {
          for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
          {
            cout << "Device: " << deviceIdx + 1 << ", vendor: " << driver.getVendorName (deviceIdx) << ", product: " << driver.getProductName (deviceIdx)
              << ", connected: " << (int) driver.getBus (deviceIdx) << " @ " << (int) driver.getAddress (deviceIdx) << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'" << endl;
          }

        }
        else
          cout << "No devices connected." << endl;

        cout <<"Virtual Devices available: ONI player" << endl;
      }
      return (0);
    }
  }
  else
  {
    openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
    if (driver.getNumberDevices () > 0)
      cout << "Device Id not set, using first device." << endl;
  }

  unsigned mode;
  if (pcl::console::parse (argc, argv, "-imagemode", mode) != -1)
    image_mode = (pcl::OpenNIGrabber::Mode) mode;

  pcl::OpenNIGrabber grabber (device_id, pcl::OpenNIGrabber::OpenNI_Default_Mode, image_mode);
  SimpleOpenNIViewer v (grabber);
  v.run ();

  return (0);
}
<commit_msg>fix openni_save_image - flip images vertically for proper orientation<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2011, Willow Garage, Inc.
 *
 *  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 Willow Garage, Inc. 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 <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <pcl/common/time.h> //fps calculations
#include <pcl/io/openni_grabber.h>
#include <pcl/io/openni_camera/openni_driver.h>
#include <pcl/console/parse.h>
#include <vtkImageViewer.h>
#include <vtkImageImport.h>
#include <vtkJPEGWriter.h>
#include <vtkBMPWriter.h>
#include <vtkPNGWriter.h>
#include <vtkTIFFWriter.h>
#include <vtkImageFlip.h>
#include <vector>
#include <string>

#include <pcl/visualization/pcl_visualizer.h>

#define SHOW_FPS 1
#if SHOW_FPS
#define FPS_CALC(_WHAT_) \
do \
{ \
    static unsigned count = 0;\
    static double last = pcl::getTime ();\
    double now = pcl::getTime (); \
    ++count; \
    if (now - last >= 1.0) \
    { \
      std::cout << "Average framerate("<< _WHAT_ << "): " << double(count)/double(now - last) << " Hz" <<  std::endl; \
      count = 0; \
      last = now; \
    } \
}while(false)
#else
#define FPS_CALC(_WHAT_) \
do \
{ \
}while(false)
#endif

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class SimpleOpenNIViewer
{
  public:
    SimpleOpenNIViewer (pcl::OpenNIGrabber& grabber)
      : grabber_ (grabber),
        importer_ (vtkSmartPointer<vtkImageImport>::New ()),
        depth_importer_ (vtkSmartPointer<vtkImageImport>::New ()),
        writer_ (vtkSmartPointer<vtkTIFFWriter>::New ()),
        flipper_ (vtkSmartPointer<vtkImageFlip>::New ())
    {
      importer_->SetNumberOfScalarComponents (3);
      importer_->SetDataScalarTypeToUnsignedChar ();
      depth_importer_->SetNumberOfScalarComponents (1);
      depth_importer_->SetDataScalarTypeToUnsignedShort ();
      writer_->SetCompressionToPackBits ();
      flipper_->SetFilteredAxes (1);
    }

    void
    image_callback (const boost::shared_ptr<openni_wrapper::Image> &image,
                    const boost::shared_ptr<openni_wrapper::DepthImage> &depth_image, float constant)
    {
      FPS_CALC ("image callback");
      boost::mutex::scoped_lock lock (image_mutex_);
      image_ = image;
      depth_image_ = depth_image;
    }

    void
    run ()
    {
      boost::function<void (const boost::shared_ptr<openni_wrapper::Image>&, const boost::shared_ptr<openni_wrapper::DepthImage>&, float) > image_cb = boost::bind (&SimpleOpenNIViewer::image_callback, this, _1, _2, _3);
      boost::signals2::connection image_connection = grabber_.registerCallback (image_cb);

      grabber_.start ();

      unsigned char* rgb_data = 0;
      unsigned rgb_data_size = 0;
      void* data;

      while (true)
      {
        boost::mutex::scoped_lock lock (image_mutex_);

        std::string time = boost::posix_time::to_iso_string (boost::posix_time::microsec_clock::local_time ());
        if (image_)
        {
          FPS_CALC ("writer callback");
          boost::shared_ptr<openni_wrapper::Image> image;
          image.swap (image_);

          if (image->getEncoding() == openni_wrapper::Image::RGB)
          {
            data = (void*)image->getMetaData ().Data ();
            importer_->SetWholeExtent (0, image->getWidth () - 1, 0, image->getHeight () - 1, 0, 0);
            importer_->SetDataExtentToWholeExtent ();
          }
          else
          {
            if (rgb_data_size < image->getWidth () * image->getHeight ())
            {
              rgb_data_size = image->getWidth () * image->getHeight ();
              rgb_data = new unsigned char [rgb_data_size * 3];
              importer_->SetWholeExtent (0, image->getWidth () - 1, 0, image->getHeight () - 1, 0, 0);
              importer_->SetDataExtentToWholeExtent ();
            }
            image->fillRGB (image->getWidth (), image->getHeight (), rgb_data);
            data = (void*)rgb_data;
          }

          std::stringstream ss;
          ss << "frame_" + time + "_rgb.tiff";
          importer_->SetImportVoidPointer (data, 1);
          importer_->Update ();
          flipper_->SetInputConnection (importer_->GetOutputPort ());
          flipper_->Update ();
          writer_->SetFileName (ss.str ().c_str ());
          writer_->SetInputConnection (flipper_->GetOutputPort ());
          writer_->Write ();
        }

        if (depth_image_)
        {
          boost::shared_ptr<openni_wrapper::DepthImage> depth_image;
          depth_image.swap (depth_image_);

          std::stringstream ss;
          ss << "frame_" + time + "_depth.tiff";

          depth_importer_->SetWholeExtent (0, depth_image->getWidth () - 1, 0, depth_image->getHeight () - 1, 0, 0);
          depth_importer_->SetDataExtentToWholeExtent ();
          depth_importer_->SetImportVoidPointer ((void*)depth_image->getDepthMetaData ().Data (), 1);
          depth_importer_->Update ();
          flipper_->SetInputConnection (depth_importer_->GetOutputPort ());
          flipper_->Update ();
          writer_->SetFileName (ss.str ().c_str ());
          writer_->SetInputConnection (flipper_->GetOutputPort ());
          writer_->Write ();
        }
      }

      grabber_.stop ();

      image_connection.disconnect ();

      if (rgb_data)
        delete[] rgb_data;
    }

    pcl::OpenNIGrabber& grabber_;
    boost::mutex image_mutex_;
    boost::shared_ptr<openni_wrapper::Image> image_;
    boost::shared_ptr<openni_wrapper::DepthImage> depth_image_;
    vtkSmartPointer<vtkImageImport> importer_, depth_importer_;
    vtkSmartPointer<vtkTIFFWriter> writer_;
    vtkSmartPointer<vtkImageFlip> flipper_;
};

void
usage (char ** argv)
{
  cout << "usage: " << argv[0] << " [((<device_id> | <path-to-oni-file>) [-imagemode <mode>] | -l [<device_id>]| -h | --help)]" << endl;
  cout << argv[0] << " -h | --help : shows this help" << endl;
  cout << argv[0] << " -l : list all available devices" << endl;
  cout << argv[0] << " -l <device-id> : list all available modes for specified device" << endl;

  cout << "                 device_id may be #1, #2, ... for the first, second etc device in the list"
#ifndef _WIN32
       << " or" << endl
       << "                 bus@address for the device connected to a specific usb-bus / address combination or" << endl
       << "                 <serial-number>"
#endif
       << endl;
  cout << endl;
  cout << "examples:" << endl;
  cout << argv[0] << " \"#1\"" << endl;
  cout << "    uses the first device." << endl;
  cout << argv[0] << " \"./temp/test.oni\"" << endl;
  cout << "    uses the oni-player device to play back oni file given by path." << endl;
  cout << argv[0] << " -l" << endl;
  cout << "    lists all available devices." << endl;
  cout << argv[0] << " -l \"#2\"" << endl;
  cout << "    lists all available modes for the second device" << endl;
#ifndef _WIN32
  cout << argv[0] << " A00361800903049A" << endl;
  cout << "    uses the device with the serial number \'A00361800903049A\'." << endl;
  cout << argv[0] << " 1@16" << endl;
  cout << "    uses the device on address 16 at USB bus 1." << endl;
#endif
  return;
}

int
main(int argc, char ** argv)
{
  std::string device_id ("");
  pcl::OpenNIGrabber::Mode image_mode = pcl::OpenNIGrabber::OpenNI_Default_Mode;

  if (argc >= 2)
  {
    device_id = argv[1];
    if (device_id == "--help" || device_id == "-h")
    {
      usage(argv);
      return 0;
    }
    else if (device_id == "-l")
    {
      if (argc >= 3)
      {
        pcl::OpenNIGrabber grabber (argv[2]);
        boost::shared_ptr<openni_wrapper::OpenNIDevice> device = grabber.getDevice ();
        std::vector<std::pair<int, XnMapOutputMode> > modes;

        if (device->hasImageStream ())
        {
          cout << endl << "Supported image modes for device: " << device->getVendorName () << " , " << device->getProductName () << endl;
          modes = grabber.getAvailableImageModes ();
          for (std::vector<std::pair<int, XnMapOutputMode> >::const_iterator it = modes.begin (); it != modes.end (); ++it)
          {
            cout << it->first << " = " << it->second.nXRes << " x " << it->second.nYRes << " @ " << it->second.nFPS << endl;
          }
        }
      }
      else
      {
        openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
        if (driver.getNumberDevices () > 0)
        {
          for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
          {
            cout << "Device: " << deviceIdx + 1 << ", vendor: " << driver.getVendorName (deviceIdx) << ", product: " << driver.getProductName (deviceIdx)
              << ", connected: " << (int) driver.getBus (deviceIdx) << " @ " << (int) driver.getAddress (deviceIdx) << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'" << endl;
          }

        }
        else
          cout << "No devices connected." << endl;

        cout <<"Virtual Devices available: ONI player" << endl;
      }
      return (0);
    }
  }
  else
  {
    openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
    if (driver.getNumberDevices () > 0)
      cout << "Device Id not set, using first device." << endl;
  }

  unsigned mode;
  if (pcl::console::parse (argc, argv, "-imagemode", mode) != -1)
    image_mode = (pcl::OpenNIGrabber::Mode) mode;

  pcl::OpenNIGrabber grabber (device_id, pcl::OpenNIGrabber::OpenNI_Default_Mode, image_mode);
  SimpleOpenNIViewer v (grabber);
  v.run ();

  return (0);
}
<|endoftext|>


<commit_before>#include "AnimationBlender.h"
#include <Animation/MappedPoseOutput.h>
#include <Scene/SceneNode.h>

namespace DEM::Anim
{
CAnimationBlender::CAnimationBlender() = default;
CAnimationBlender::~CAnimationBlender() = default;

void CAnimationBlender::Initialize(U8 SourceCount, U8 PortCount)
{
	_Sources.clear();
	_Sources.reserve(SourceCount);
	for (U8 i = 0; i < SourceCount; ++i)
		_Sources.emplace_back(*this, i);

	// All sources initially have the same priority, order is not important
	_SourcesByPriority.resize(SourceCount);
	for (U8 i = 0; i < SourceCount; ++i)
		_SourcesByPriority[i] = i;
	_PrioritiesChanged = false;

	// Allocate blend matrix (sources * ports)
	const auto MatrixCellCount = PortCount * SourceCount;
	_Transforms.resize(MatrixCellCount);
	_ChannelMasks.resize(MatrixCellCount, 0);

	_PortCount = PortCount;
}
//---------------------------------------------------------------------

void CAnimationBlender::EvaluatePose(IPoseOutput& Output)
{
	const auto SourceCount = _Sources.size();
	if (!SourceCount) return;

	if (_PrioritiesChanged)
	{
		std::sort(_SourcesByPriority.begin(), _SourcesByPriority.end(), [this](U8 a, U8 b)
		{
			return _Sources[a]._Priority > _Sources[b]._Priority;
		});
		_PrioritiesChanged = false;
	}

	for (UPTR Port = 0; Port < _PortCount; ++Port)
	{
		Math::CTransformSRT FinalTfm;
		U8 FinalMask = 0;
		float ScaleWeights = 0.f;
		float RotationWeights = 0.f;
		float TranslationWeights = 0.f;

		const auto Offset = Port * SourceCount;

		for (const U8 SourceIndex : _SourcesByPriority)
		{
			const float SourceWeight = _Sources[SourceIndex]._Weight;
			if (SourceWeight <= 0.f) continue;

			const auto& CurrTfm = _Transforms[Offset + SourceIndex];
			const U8 ChannelMask = _ChannelMasks[Offset + SourceIndex];

			if ((ChannelMask & ETransformChannel::Scaling) && ScaleWeights < 1.f)
			{
				const float Weight = std::min(SourceWeight, 1.f - ScaleWeights);

				// Scale is 1.f by default. To blend correctly, we must reset it to zero before applying the first source.
				if (FinalMask & ETransformChannel::Scaling)
					FinalTfm.Scale += CurrTfm.Scale * Weight;
				else
					FinalTfm.Scale = CurrTfm.Scale * Weight;

				FinalMask |= ETransformChannel::Scaling;
				ScaleWeights += Weight;
			}

			if ((ChannelMask & ETransformChannel::Rotation) && RotationWeights < 1.f)
			{
				const float Weight = std::min(SourceWeight, 1.f - RotationWeights);

				// TODO: check this hardcore stuff for multiple quaternion blending:
				// https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872.pdf
				// Impl: http://wiki.unity3d.com/index.php/Averaging_Quaternions_and_Vectors
				// Impl: https://github.com/christophhagen/averaging-quaternions/blob/master/averageQuaternions.py
				if (FinalMask & ETransformChannel::Rotation)
				{
					quaternion Q;
					Q.slerp(quaternion::Identity, CurrTfm.Rotation, Weight);
					FinalTfm.Rotation *= Q;
				}
				else
				{
					FinalTfm.Rotation.slerp(quaternion::Identity, CurrTfm.Rotation, Weight);
				}

				FinalMask |= ETransformChannel::Rotation;
				RotationWeights += Weight;
			}

			if ((ChannelMask & ETransformChannel::Translation) && TranslationWeights < 1.f)
			{
				const float Weight = std::min(SourceWeight, 1.f - TranslationWeights);
				FinalTfm.Translation += CurrTfm.Translation * Weight;
				FinalMask |= ETransformChannel::Translation;
				TranslationWeights += Weight;
			}
		}

		// Apply accumulated transform

		if (FinalMask & ETransformChannel::Scaling)
			Output.SetScale(Port, FinalTfm.Scale);

		if (FinalMask & ETransformChannel::Rotation)
		{
			if (RotationWeights < 1.f) FinalTfm.Rotation.normalize();
			Output.SetRotation(Port, FinalTfm.Rotation);
		}

		if (FinalMask & ETransformChannel::Translation)
			Output.SetTranslation(Port, FinalTfm.Translation);
	}

	// Source data is blended into the output, no more channels are ready to be blended
	std::memset(_ChannelMasks.data(), 0, _ChannelMasks.size());
}
//---------------------------------------------------------------------

void CAnimationBlender::SetPriority(U8 Source, U16 Priority)
{
	if (Source < _Sources.size() && _Sources[Source]._Priority != Priority)
	{
		_Sources[Source]._Priority = Priority;
		_PrioritiesChanged = true;
	}
}
//---------------------------------------------------------------------

void CAnimationBlender::SetWeight(U8 Source, float Weight)
{
	if (Source < _Sources.size()) _Sources[Source]._Weight = Weight;
}
//---------------------------------------------------------------------

}
<commit_msg>Quaternion blending fixed<commit_after>#include "AnimationBlender.h"
#include <Animation/MappedPoseOutput.h>
#include <Scene/SceneNode.h>

namespace DEM::Anim
{
CAnimationBlender::CAnimationBlender() = default;
CAnimationBlender::~CAnimationBlender() = default;

void CAnimationBlender::Initialize(U8 SourceCount, U8 PortCount)
{
	_Sources.clear();
	_Sources.reserve(SourceCount);
	for (U8 i = 0; i < SourceCount; ++i)
		_Sources.emplace_back(*this, i);

	// All sources initially have the same priority, order is not important
	_SourcesByPriority.resize(SourceCount);
	for (U8 i = 0; i < SourceCount; ++i)
		_SourcesByPriority[i] = i;
	_PrioritiesChanged = false;

	// Allocate blend matrix (sources * ports)
	const auto MatrixCellCount = PortCount * SourceCount;
	_Transforms.resize(MatrixCellCount);
	_ChannelMasks.resize(MatrixCellCount, 0);

	_PortCount = PortCount;
}
//---------------------------------------------------------------------

void CAnimationBlender::EvaluatePose(IPoseOutput& Output)
{
	const auto SourceCount = _Sources.size();
	if (!SourceCount) return;

	if (_PrioritiesChanged)
	{
		std::sort(_SourcesByPriority.begin(), _SourcesByPriority.end(), [this](U8 a, U8 b)
		{
			return _Sources[a]._Priority > _Sources[b]._Priority;
		});
		_PrioritiesChanged = false;
	}

	for (UPTR Port = 0; Port < _PortCount; ++Port)
	{
		Math::CTransformSRT FinalTfm;
		U8 FinalMask = 0;
		float ScaleWeights = 0.f;
		float RotationWeights = 0.f;
		float TranslationWeights = 0.f;

		const auto Offset = Port * SourceCount;

		for (const U8 SourceIndex : _SourcesByPriority)
		{
			const float SourceWeight = _Sources[SourceIndex]._Weight;
			if (SourceWeight <= 0.f) continue;

			const auto& CurrTfm = _Transforms[Offset + SourceIndex];
			const U8 ChannelMask = _ChannelMasks[Offset + SourceIndex];

			if ((ChannelMask & ETransformChannel::Scaling) && ScaleWeights < 1.f)
			{
				const float Weight = std::min(SourceWeight, 1.f - ScaleWeights);

				// Scale is 1.f by default. To blend correctly, we must reset it to zero before applying the first source.
				if (FinalMask & ETransformChannel::Scaling)
					FinalTfm.Scale += CurrTfm.Scale * Weight;
				else
					FinalTfm.Scale = CurrTfm.Scale * Weight;

				FinalMask |= ETransformChannel::Scaling;
				ScaleWeights += Weight;
			}

			if ((ChannelMask & ETransformChannel::Rotation) && RotationWeights < 1.f)
			{
				const float Weight = std::min(SourceWeight, 1.f - RotationWeights);

				quaternion Q;
				Q.x = CurrTfm.Rotation.x * Weight;
				Q.y = CurrTfm.Rotation.y * Weight;
				Q.z = CurrTfm.Rotation.z * Weight;
				Q.w = CurrTfm.Rotation.w * Weight;

				if (FinalMask & ETransformChannel::Rotation)
				{
					// Blend with shortest arc, based on a 4D dot product sign
					if (Q.x * FinalTfm.Rotation.x + Q.y * FinalTfm.Rotation.y + Q.z * FinalTfm.Rotation.z + Q.w * FinalTfm.Rotation.w < 0.f)
						FinalTfm.Rotation -= Q;
					else
						FinalTfm.Rotation += Q;
				}
				else
				{
					FinalTfm.Rotation = Q;
				}

				FinalMask |= ETransformChannel::Rotation;
				RotationWeights += Weight;
			}

			if ((ChannelMask & ETransformChannel::Translation) && TranslationWeights < 1.f)
			{
				const float Weight = std::min(SourceWeight, 1.f - TranslationWeights);
				FinalTfm.Translation += CurrTfm.Translation * Weight;
				FinalMask |= ETransformChannel::Translation;
				TranslationWeights += Weight;
			}
		}

		// Apply accumulated transform

		if (FinalMask & ETransformChannel::Scaling)
			Output.SetScale(Port, FinalTfm.Scale);

		if (FinalMask & ETransformChannel::Rotation)
		{
			if (RotationWeights < 1.f) FinalTfm.Rotation.normalize();
			Output.SetRotation(Port, FinalTfm.Rotation);
		}

		if (FinalMask & ETransformChannel::Translation)
			Output.SetTranslation(Port, FinalTfm.Translation);
	}

	// Source data is blended into the output, no more channels are ready to be blended
	std::memset(_ChannelMasks.data(), 0, _ChannelMasks.size());
}
//---------------------------------------------------------------------

void CAnimationBlender::SetPriority(U8 Source, U16 Priority)
{
	if (Source < _Sources.size() && _Sources[Source]._Priority != Priority)
	{
		_Sources[Source]._Priority = Priority;
		_PrioritiesChanged = true;
	}
}
//---------------------------------------------------------------------

void CAnimationBlender::SetWeight(U8 Source, float Weight)
{
	if (Source < _Sources.size()) _Sources[Source]._Weight = Weight;
}
//---------------------------------------------------------------------

}
<|endoftext|>


<commit_before>#include <Arduino.h>
#include "uplink.h"
#include "main.h"
#include "usonic.h"

extern "C" {
    #include "pb.h"
    #include "pb_encode.h"
    #include "pb_decode.h"
    #include "status.pb.h"
    #include "sensor.pb.h"
    #include "odometry.h"
    #include "battery.h"
}

uint8_t uplink_send_buffer[BUFFERSIZE];

void uplink_setup(void){
  Serial.begin(UPLINK_SPEED);
}

void uplink_sendStatus(void){

    antikeimena_Status status_pb;

    status_pb.version       = 12;
    status_pb.uptime        = 13;
    status_pb.sensorInError = 14;

    pb_ostream_t stream = pb_ostream_from_buffer(uplink_send_buffer, sizeof(uplink_send_buffer));
    pb_encode(&stream, antikeimena_Status_fields, &status_pb);

    uint16_t s = antikeimena_Status_size;

    Serial.write("ANSI");
    Serial.write(STATUS_MESSAGE);

    Serial.write( (s     ) & 0xFF); // low
    Serial.write( (s >> 8) & 0xFF); // high

    for(uint32_t i = 0; i < antikeimena_Status_size; i++) {
        Serial.write(uplink_send_buffer[i]);
    }

}

void uplink_sendSensor(void){

    antikeimena_Sensor sensor_pb = antikeimena_Sensor_init_zero;

    sensor_pb.odometry_left   = odometry_get_left_counter();
    sensor_pb.odometry_right  = odometry_get_right_counter();
    sensor_pb.battery_voltage = battery_voltage;
    sensor_pb.ultrasonic_01   = ultrasonic_distance[0];
    sensor_pb.ultrasonic_02   = ultrasonic_distance[1];
    sensor_pb.ultrasonic_03   = ultrasonic_distance[2];
    sensor_pb.ultrasonic_04   = ultrasonic_distance[3];
    sensor_pb.ultrasonic_05   = ultrasonic_distance[4];
    sensor_pb.ultrasonic_06   = ultrasonic_distance[5];
    sensor_pb.ultrasonic_07   = ultrasonic_distance[6];
    sensor_pb.ultrasonic_08   = ultrasonic_distance[7];
    sensor_pb.ultrasonic_09   = ultrasonic_distance[8];
    sensor_pb.ultrasonic_10   = ultrasonic_distance[9];

    pb_ostream_t stream = pb_ostream_from_buffer(uplink_send_buffer, sizeof(uplink_send_buffer));
    pb_encode(&stream, antikeimena_Sensor_fields, &sensor_pb);

    uint16_t mysize = stream.bytes_written;

    Serial.write("ANSI");
    Serial.flush();

    Serial.write(SENSOR_MESSAGE);
    Serial.flush();

    Serial.write( (mysize     ) & 0xFF); // low
    Serial.write( (mysize >> 8) & 0xFF); // high
    Serial.flush();

    for(uint32_t i = 0; i < mysize; i++) {
        Serial.write(uplink_send_buffer[i]);
    }
    Serial.flush();

}<commit_msg>Fixing protobuf error<commit_after>#include <Arduino.h>
#include "uplink.h"
#include "main.h"
#include "usonic.h"

extern "C" {
    #include "pb.h"
    #include "pb_encode.h"
    #include "pb_decode.h"
    #include "status.pb.h"
    #include "sensor.pb.h"
    #include "odometry.h"
    #include "battery.h"
}

uint8_t uplink_send_buffer[BUFFERSIZE];

void uplink_setup(void){
  Serial.begin(UPLINK_SPEED);
}

void uplink_sendStatus(void){

    antikeimena_Status status_pb = antikeimena_Status_init_zero;

    status_pb.version       = 12;
    status_pb.uptime        = 13;
    status_pb.sensorInError = 14;

    pb_ostream_t stream = pb_ostream_from_buffer(uplink_send_buffer, sizeof(uplink_send_buffer));
    pb_encode(&stream, antikeimena_Status_fields, &status_pb);

    uint16_t mysize = stream.bytes_written;

    Serial.write("ANSI");
    Serial.flush();

    Serial.write(STATUS_MESSAGE);
    Serial.flush();

    Serial.write( (mysize     ) & 0xFF); // low
    Serial.write( (mysize >> 8) & 0xFF); // high
    Serial.flush();

    for(uint32_t i = 0; i < mysize; i++) {
        Serial.write(uplink_send_buffer[i]);
    }
    Serial.flush();
}

void uplink_sendSensor(void){

    antikeimena_Sensor sensor_pb = antikeimena_Sensor_init_zero;

    sensor_pb.odometry_left   = odometry_get_left_counter();
    sensor_pb.odometry_right  = odometry_get_right_counter();
    sensor_pb.battery_voltage = battery_voltage;
    sensor_pb.ultrasonic_01   = ultrasonic_distance[0];
    sensor_pb.ultrasonic_02   = ultrasonic_distance[1];
    sensor_pb.ultrasonic_03   = ultrasonic_distance[2];
    sensor_pb.ultrasonic_04   = ultrasonic_distance[3];
    sensor_pb.ultrasonic_05   = ultrasonic_distance[4];
    sensor_pb.ultrasonic_06   = ultrasonic_distance[5];
    sensor_pb.ultrasonic_07   = ultrasonic_distance[6];
    sensor_pb.ultrasonic_08   = ultrasonic_distance[7];
    sensor_pb.ultrasonic_09   = ultrasonic_distance[8];
    sensor_pb.ultrasonic_10   = ultrasonic_distance[9];

    pb_ostream_t stream = pb_ostream_from_buffer(uplink_send_buffer, sizeof(uplink_send_buffer));
    pb_encode(&stream, antikeimena_Sensor_fields, &sensor_pb);

    uint16_t mysize = stream.bytes_written;

    Serial.write("ANSI");
    Serial.flush();

    Serial.write(SENSOR_MESSAGE);
    Serial.flush();

    Serial.write( (mysize     ) & 0xFF); // low
    Serial.write( (mysize >> 8) & 0xFF); // high
    Serial.flush();

    for(uint32_t i = 0; i < mysize; i++) {
        Serial.write(uplink_send_buffer[i]);
    }
    Serial.flush();

}<|endoftext|>