<commit_before>#include "ContactListener.h"

#include <sofa/core/collision/NarrowPhaseDetection.h>
#include <sofa/core/collision/ContactManager.h>

#include <sofa/core/CollisionModel.h>
#include <sofa/core/ObjectFactory.h>
#include <sofa/simulation/common/Node.h>
#include <sofa/simulation/common/CollisionBeginEvent.h>
#include <sofa/simulation/common/CollisionEndEvent.h>

namespace sofa
{
	namespace core
	{

		namespace collision
		{

			SOFA_DECL_CLASS(ContactListener);
			int ContactListenerClass = core::RegisterObject("ContactListener .. ").add< ContactListener >();

			ContactListener::ContactListener(  CollisionModel* collModel1 , CollisionModel* collModel2 )
				:
				  //mLinkCollisionModel1( initLink("collisionModel1", "first collision model"), collModel1 )
				//, mLinkCollisionModel2( initLink("collisionModel2", "second collision model"), collModel2 )
				 mNarrowPhase(NULL)
			{
				mCollisionModel1 = collModel1;
				mCollisionModel2 = collModel2;
			}

			ContactListener::~ContactListener()
			{
			}

			void ContactListener::init(void)
			{
				helper::vector<ContactManager*> contactManagers;

				mNarrowPhase = getContext()->get<core::collision::NarrowPhaseDetection>();
				if ( mNarrowPhase != NULL )
				{
					// add to the event listening
					f_listening.setValue(true);

				}

			}

			void ContactListener::handleEvent( core::objectmodel::Event* _event )
			{
				if (dynamic_cast<simulation::CollisionBeginEvent *>(_event))
				{
					mContactsVector.clear();
				}

				else if (dynamic_cast<simulation::CollisionEndEvent *>(_event))
				{

					const NarrowPhaseDetection::DetectionOutputMap& detectionOutputsMap = mNarrowPhase->getDetectionOutputs();

					if ( detectionOutputsMap.size() == 0 )
					{
						endContact(NULL);
						return;
					}

					//core::collision::NarrowPhaseDetection::DetectionOutputMap::iterator it = detectionOutputsMap.begin();
					//const helper::vector<DetectionOutput>* detection = dynamic_cast<helper::vector<DetectionOutput>*>(it->second);
					//const TDetectionOutputVector<mCollisionModel1,mCollisionModel2>* detection = dynamic_cast<TDetectionOutputVector*>(it->second);

					if  ( mCollisionModel2 == NULL )
					{
						//// check only one collision model
						for (core::collision::NarrowPhaseDetection::DetectionOutputMap::const_iterator it = detectionOutputsMap.begin(); it!=detectionOutputsMap.end(); ++it )
						{
							const CollisionModel* collMod1 = it->first.first;
							const CollisionModel* collMod2 = it->first.second;

							if ( mCollisionModel1 == collMod1 || mCollisionModel1 == collMod2 )
							{
								if ( const helper::vector<DetectionOutput>* contacts = dynamic_cast<helper::vector<DetectionOutput>*>(it->second) )
								{
									mContactsVector.push_back( contacts );
								}
							}
						}
					}
					else
					{
						// check both collision models
						for (core::collision::NarrowPhaseDetection::DetectionOutputMap::const_iterator it = detectionOutputsMap.begin(); it!=detectionOutputsMap.end(); ++it )
						{
							const CollisionModel* collMod1 = it->first.first;
							const CollisionModel* collMod2 = it->first.second;

							if ( (mCollisionModel1==collMod1 && mCollisionModel2==collMod2) || (mCollisionModel1==collMod2 && mCollisionModel2==collMod1) )
							{
								if ( const helper::vector<DetectionOutput>* contacts = dynamic_cast<helper::vector<DetectionOutput>*>(it->second) )
								{
									mContactsVector.push_back( contacts );
								}
							}
						}

					}

					beginContact(mContactsVector);

				}

			}

		} // namespace collision

	} // namespace core

} // namespace sofa
<commit_msg>r9797/sofa : Fix: Removed problem (unneeded) include in ContactListener<commit_after>#include "ContactListener.h"

#include <sofa/core/collision/NarrowPhaseDetection.h>
#include <sofa/core/collision/ContactManager.h>

#include <sofa/core/CollisionModel.h>
#include <sofa/core/ObjectFactory.h>
#include <sofa/simulation/common/CollisionBeginEvent.h>
#include <sofa/simulation/common/CollisionEndEvent.h>

namespace sofa
{
	namespace core
	{

		namespace collision
		{

			SOFA_DECL_CLASS(ContactListener);
			int ContactListenerClass = core::RegisterObject("ContactListener .. ").add< ContactListener >();

			ContactListener::ContactListener(  CollisionModel* collModel1 , CollisionModel* collModel2 )
				:
				  //mLinkCollisionModel1( initLink("collisionModel1", "first collision model"), collModel1 )
				//, mLinkCollisionModel2( initLink("collisionModel2", "second collision model"), collModel2 )
				 mNarrowPhase(NULL)
			{
				mCollisionModel1 = collModel1;
				mCollisionModel2 = collModel2;
			}

			ContactListener::~ContactListener()
			{
			}

			void ContactListener::init(void)
			{
				helper::vector<ContactManager*> contactManagers;

				mNarrowPhase = getContext()->get<core::collision::NarrowPhaseDetection>();
				if ( mNarrowPhase != NULL )
				{
					// add to the event listening
					f_listening.setValue(true);

				}

			}

			void ContactListener::handleEvent( core::objectmodel::Event* _event )
			{
				if (dynamic_cast<simulation::CollisionBeginEvent *>(_event))
				{
					mContactsVector.clear();
				}

				else if (dynamic_cast<simulation::CollisionEndEvent *>(_event))
				{

					const NarrowPhaseDetection::DetectionOutputMap& detectionOutputsMap = mNarrowPhase->getDetectionOutputs();

					if ( detectionOutputsMap.size() == 0 )
					{
						endContact(NULL);
						return;
					}

					//core::collision::NarrowPhaseDetection::DetectionOutputMap::iterator it = detectionOutputsMap.begin();
					//const helper::vector<DetectionOutput>* detection = dynamic_cast<helper::vector<DetectionOutput>*>(it->second);
					//const TDetectionOutputVector<mCollisionModel1,mCollisionModel2>* detection = dynamic_cast<TDetectionOutputVector*>(it->second);

					if  ( mCollisionModel2 == NULL )
					{
						//// check only one collision model
						for (core::collision::NarrowPhaseDetection::DetectionOutputMap::const_iterator it = detectionOutputsMap.begin(); it!=detectionOutputsMap.end(); ++it )
						{
							const CollisionModel* collMod1 = it->first.first;
							const CollisionModel* collMod2 = it->first.second;

							if ( mCollisionModel1 == collMod1 || mCollisionModel1 == collMod2 )
							{
								if ( const helper::vector<DetectionOutput>* contacts = dynamic_cast<helper::vector<DetectionOutput>*>(it->second) )
								{
									mContactsVector.push_back( contacts );
								}
							}
						}
					}
					else
					{
						// check both collision models
						for (core::collision::NarrowPhaseDetection::DetectionOutputMap::const_iterator it = detectionOutputsMap.begin(); it!=detectionOutputsMap.end(); ++it )
						{
							const CollisionModel* collMod1 = it->first.first;
							const CollisionModel* collMod2 = it->first.second;

							if ( (mCollisionModel1==collMod1 && mCollisionModel2==collMod2) || (mCollisionModel1==collMod2 && mCollisionModel2==collMod1) )
							{
								if ( const helper::vector<DetectionOutput>* contacts = dynamic_cast<helper::vector<DetectionOutput>*>(it->second) )
								{
									mContactsVector.push_back( contacts );
								}
							}
						}

					}

					beginContact(mContactsVector);

				}

			}

		} // namespace collision

	} // namespace core

} // namespace sofa
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fontmenucontroller.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 14:19:33 $
 *
 *  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_framework.hxx"

#ifndef __FRAMEWORK_UIELEMENT_FONTMENUCONTROLLER_HXX_
#include <uielement/fontmenucontroller.hxx>
#endif

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#ifndef __FRAMEWORK_THREADHELP_RESETABLEGUARD_HXX_
#include <threadhelp/resetableguard.hxx>
#endif

#ifndef __FRAMEWORK_SERVICES_H_
#include "services.h"
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_AWT_XDEVICE_HPP_
#include <com/sun/star/awt/XDevice.hpp>
#endif

#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#ifndef _COM_SUN_STAR_AWT_MENUITEMSTYLE_HPP_
#include <com/sun/star/awt/MenuItemStyle.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
#include <com/sun/star/util/XURLTransformer.hpp>
#endif

#ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_
#include <com/sun/star/frame/XDispatchProvider.hpp>
#endif

//_________________________________________________________________________________________________________________
//  includes of other projects
//_________________________________________________________________________________________________________________

#ifndef _VCL_MENU_HXX_
#include <vcl/menu.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _VCL_I18NHELP_HXX
#include <vcl/i18nhelp.hxx>
#endif
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif
#ifndef _VCL_MNEMONIC_HXX_
#include <vcl/mnemonic.hxx>
#endif

//_________________________________________________________________________________________________________________
//  Defines
//_________________________________________________________________________________________________________________
//

using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::frame;
using namespace com::sun::star::beans;
using namespace com::sun::star::util;

namespace framework
{

DEFINE_XSERVICEINFO_MULTISERVICE        (   FontMenuController                      ,
                                            OWeakObject                             ,
                                            SERVICENAME_POPUPMENUCONTROLLER         ,
                                            IMPLEMENTATIONNAME_FONTMENUCONTROLLER
                                        )

DEFINE_INIT_SERVICE                     (   FontMenuController, {} )

FontMenuController::FontMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) :
    PopupMenuControllerBase( xServiceManager )
{
}

FontMenuController::~FontMenuController()
{
}

// private function
void FontMenuController::fillPopupMenu( const Sequence< ::rtl::OUString >& rFontNameSeq, Reference< css::awt::XPopupMenu >& rPopupMenu )
{
    const rtl::OUString*    pFontNameArray = rFontNameSeq.getConstArray();
    VCLXPopupMenu*          pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu );
    PopupMenu*              pVCLPopupMenu = 0;

    vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );

    resetPopupMenu( rPopupMenu );
    if ( pPopupMenu )
        pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();

    if ( pVCLPopupMenu )
    {
        rtl::OUString aEmpty;
        const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();

        for ( USHORT i = 0; i < rFontNameSeq.getLength(); i++ )
        {
            const rtl::OUString& rName = pFontNameArray[i];

            USHORT j = m_xPopupMenu->getItemCount();
            while ( j )
            {
                rtl::OUString aText = m_xPopupMenu->getItemText( m_xPopupMenu->getItemId( j-1 ) );

                String aString = MnemonicGenerator::EraseAllMnemonicChars( aText );
                if ( rI18nHelper.CompareString( rName, aString ) > 0 )
                    break;
                j--;
            }

            m_xPopupMenu->insertItem( i+1, rName, css::awt::MenuItemStyle::RADIOCHECK | css::awt::MenuItemStyle::AUTOCHECK, j );
            if ( rName == m_aFontFamilyName )
                m_xPopupMenu->checkItem( i+1, sal_True );

            // use VCL popup menu pointer to set vital information that are not part of the awt implementation
            pVCLPopupMenu->SetItemCommand( i+1, rName ); // Store font name into item command.
        }
    }
}

// XEventListener
void SAL_CALL FontMenuController::disposing( const EventObject& ) throw ( RuntimeException )
{
    Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );

    ResetableGuard aLock( m_aLock );
    m_xFrame.clear();
    m_xDispatch.clear();
    m_xFontListDispatch.clear();
    if ( m_xPopupMenu.is() )
        m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
    m_xPopupMenu.clear();
}

// XStatusListener
void SAL_CALL FontMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException )
{
    com::sun::star::awt::FontDescriptor aFontDescriptor;
    Sequence< rtl::OUString >           aFontNameSeq;

    if ( Event.State >>= aFontDescriptor )
    {
        ResetableGuard aLock( m_aLock );
        m_aFontFamilyName = aFontDescriptor.Name;
    }
    else if ( Event.State >>= aFontNameSeq )
    {
        ResetableGuard aLock( m_aLock );
        if ( m_xPopupMenu.is() )
            fillPopupMenu( aFontNameSeq, m_xPopupMenu );
    }
}

// XMenuListener
void SAL_CALL FontMenuController::highlight( const css::awt::MenuEvent& ) throw (RuntimeException)
{
}

void SAL_CALL FontMenuController::select( const css::awt::MenuEvent& rEvent ) throw (RuntimeException)
{
    Reference< css::awt::XPopupMenu >   xPopupMenu;
    Reference< XDispatch >              xDispatch;
    Reference< XMultiServiceFactory >   xServiceManager;

    ResetableGuard aLock( m_aLock );
    xPopupMenu      = m_xPopupMenu;
    xDispatch       = m_xDispatch;
    xServiceManager = m_xServiceManager;
    aLock.unlock();

    if ( xPopupMenu.is() && xDispatch.is() )
    {
        VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( xPopupMenu );
        if ( pPopupMenu )
        {
            // Command URL used to dispatch the selected font family name
            const rtl::OUString aFontNameCommand( RTL_CONSTASCII_USTRINGPARAM( ".uno:CharFontName?CharFontName.FamilyName:string=" ));

            css::util::URL               aTargetURL;
            Sequence<PropertyValue>      aArgs;
            Reference< XURLTransformer > xURLTransformer( xServiceManager->createInstance(
                                                            rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
                                                        UNO_QUERY );

            {
                vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
                PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();

                rtl::OUStringBuffer aCommandBuffer( aFontNameCommand );
                aCommandBuffer.append( INetURLObject::encode( pVCLPopupMenu->GetItemCommand( rEvent.MenuId ), INetURLObject::PART_HTTP_QUERY, '%', INetURLObject::ENCODE_ALL ));
                aTargetURL.Complete = aCommandBuffer.makeStringAndClear();
            }

            xURLTransformer->parseStrict( aTargetURL );
            xDispatch->dispatch( aTargetURL, aArgs );
        }
    }
}

void SAL_CALL FontMenuController::activate( const css::awt::MenuEvent& ) throw (RuntimeException)
{
    ResetableGuard aLock( m_aLock );

    if ( m_xPopupMenu.is() )
    {
        // find new font name and set check mark!
        USHORT        nChecked = 0;
        USHORT        nItemCount = m_xPopupMenu->getItemCount();
        rtl::OUString aEmpty;
        for( USHORT i = 0; i < nItemCount; i++ )
        {
            USHORT nItemId = m_xPopupMenu->getItemId( i );

            if ( m_xPopupMenu->isItemChecked( nItemId ) )
                nChecked = nItemId;

            rtl::OUString aText = m_xPopupMenu->getItemText( nItemId );

            // TODO: must be replaced by implementation of VCL, when available
            sal_Int32 nIndex = aText.indexOf( (sal_Unicode)'~' );
            if ( nIndex >= 0 )
                aText = aText.replaceAt( nIndex, 1, aEmpty );
            // TODO: must be replaced by implementation of VCL, when available

            if ( aText == m_aFontFamilyName )
            {
                m_xPopupMenu->checkItem( nItemId, sal_True );
                return;
            }
        }

        if ( nChecked )
            m_xPopupMenu->checkItem( nChecked, sal_False );
    }
}

void SAL_CALL FontMenuController::deactivate( const css::awt::MenuEvent& ) throw (RuntimeException)
{
}

// XPopupMenuController
void SAL_CALL FontMenuController::setPopupMenu( const Reference< css::awt::XPopupMenu >& xPopupMenu ) throw (RuntimeException)
{
    ResetableGuard aLock( m_aLock );

    if ( m_xFrame.is() && !m_xPopupMenu.is() )
    {
        // Create popup menu on demand
        vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );

        m_xPopupMenu = xPopupMenu;
        m_xPopupMenu->addMenuListener( Reference< css::awt::XMenuListener >( (OWeakObject*)this, UNO_QUERY ));

        Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
                                                        rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
                                                    UNO_QUERY );
        Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );

        com::sun::star::util::URL aTargetURL;
        aTargetURL.Complete = m_aCommandURL;
        xURLTransformer->parseStrict( aTargetURL );
        m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );

        // Register for font list updates to get the current font list from the controller
        aTargetURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontNameList" ));
        xURLTransformer->parseStrict( aTargetURL );
        m_xFontListDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );

        updatePopupMenu();
    }
}

void SAL_CALL FontMenuController::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException )
{
    PopupMenuControllerBase::updatePopupMenu();

    ResetableGuard aLock( m_aLock );
    Reference< XDispatch > xDispatch( m_xFontListDispatch );
    Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
                                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
                                                UNO_QUERY );
    com::sun::star::util::URL aTargetURL;
    aTargetURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontNameList" ));
    xURLTransformer->parseStrict( aTargetURL );
    aLock.unlock();

    if ( xDispatch.is() )
    {
        xDispatch->addStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
        xDispatch->removeStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
    }
}

// XInitialization
void SAL_CALL FontMenuController::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException )
{
    const rtl::OUString aFrameName( RTL_CONSTASCII_USTRINGPARAM( "Frame" ));
    const rtl::OUString aCommandURLName( RTL_CONSTASCII_USTRINGPARAM( "CommandURL" ));

    ResetableGuard aLock( m_aLock );

    sal_Bool bInitalized( m_bInitialized );
    if ( !bInitalized )
    {
        PropertyValue       aPropValue;
        rtl::OUString       aCommandURL;
        Reference< XFrame > xFrame;

        for ( int i = 0; i < aArguments.getLength(); i++ )
        {
            if ( aArguments[i] >>= aPropValue )
            {
                if ( aPropValue.Name.equalsAscii( "Frame" ))
                    aPropValue.Value >>= xFrame;
                else if ( aPropValue.Name.equalsAscii( "CommandURL" ))
                    aPropValue.Value >>= aCommandURL;
            }
        }

        if ( xFrame.is() && aCommandURL.getLength() )
        {
            m_xFrame        = xFrame;
            m_aCommandURL   = aCommandURL;

            m_bInitialized = sal_True;
        }
    }
}

}
<commit_msg>INTEGRATION: CWS fwk54 (1.5.14); FILE MERGED 2006/11/10 12:56:38 cd 1.5.14.1: #i65187# Extended base class and adapt popup menu controllers to be testtool compliant<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fontmenucontroller.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-13 15:07:08 $
 *
 *  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_framework.hxx"

#ifndef __FRAMEWORK_UIELEMENT_FONTMENUCONTROLLER_HXX_
#include <uielement/fontmenucontroller.hxx>
#endif

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#ifndef __FRAMEWORK_THREADHELP_RESETABLEGUARD_HXX_
#include <threadhelp/resetableguard.hxx>
#endif

#ifndef __FRAMEWORK_SERVICES_H_
#include "services.h"
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_AWT_XDEVICE_HPP_
#include <com/sun/star/awt/XDevice.hpp>
#endif

#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#ifndef _COM_SUN_STAR_AWT_MENUITEMSTYLE_HPP_
#include <com/sun/star/awt/MenuItemStyle.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
#include <com/sun/star/util/XURLTransformer.hpp>
#endif

#ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_
#include <com/sun/star/frame/XDispatchProvider.hpp>
#endif

//_________________________________________________________________________________________________________________
//  includes of other projects
//_________________________________________________________________________________________________________________

#ifndef _VCL_MENU_HXX_
#include <vcl/menu.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _VCL_I18NHELP_HXX
#include <vcl/i18nhelp.hxx>
#endif
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif
#ifndef _VCL_MNEMONIC_HXX_
#include <vcl/mnemonic.hxx>
#endif

//_________________________________________________________________________________________________________________
//  Defines
//_________________________________________________________________________________________________________________
//

using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::frame;
using namespace com::sun::star::beans;
using namespace com::sun::star::util;

namespace framework
{

DEFINE_XSERVICEINFO_MULTISERVICE        (   FontMenuController                      ,
                                            OWeakObject                             ,
                                            SERVICENAME_POPUPMENUCONTROLLER         ,
                                            IMPLEMENTATIONNAME_FONTMENUCONTROLLER
                                        )

DEFINE_INIT_SERVICE                     (   FontMenuController, {} )

FontMenuController::FontMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) :
    PopupMenuControllerBase( xServiceManager )
{
}

FontMenuController::~FontMenuController()
{
}

// private function
void FontMenuController::fillPopupMenu( const Sequence< ::rtl::OUString >& rFontNameSeq, Reference< css::awt::XPopupMenu >& rPopupMenu )
{
    const rtl::OUString*    pFontNameArray = rFontNameSeq.getConstArray();
    VCLXPopupMenu*          pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu );
    PopupMenu*              pVCLPopupMenu = 0;

    vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );

    resetPopupMenu( rPopupMenu );
    if ( pPopupMenu )
        pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();

    if ( pVCLPopupMenu )
    {
        rtl::OUString aEmpty;
        const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
        const rtl::OUString aFontNameCommandPrefix( RTL_CONSTASCII_USTRINGPARAM( ".uno:CharFontName?CharFontName.FamilyName:string=" ));

        for ( USHORT i = 0; i < rFontNameSeq.getLength(); i++ )
        {
            const rtl::OUString& rName = pFontNameArray[i];

            USHORT j = m_xPopupMenu->getItemCount();
            while ( j )
            {
                rtl::OUString aText = m_xPopupMenu->getItemText( m_xPopupMenu->getItemId( j-1 ) );

                String aString = MnemonicGenerator::EraseAllMnemonicChars( aText );
                if ( rI18nHelper.CompareString( rName, aString ) > 0 )
                    break;
                j--;
            }

            m_xPopupMenu->insertItem( i+1, rName, css::awt::MenuItemStyle::RADIOCHECK | css::awt::MenuItemStyle::AUTOCHECK, j );
            if ( rName == m_aFontFamilyName )
                m_xPopupMenu->checkItem( i+1, sal_True );

            // use VCL popup menu pointer to set vital information that are not part of the awt implementation
            rtl::OUStringBuffer aCommandBuffer( aFontNameCommandPrefix );
            aCommandBuffer.append( INetURLObject::encode( rName, INetURLObject::PART_HTTP_QUERY, '%', INetURLObject::ENCODE_ALL ));

            rtl::OUString aFontNameCommand = aCommandBuffer.makeStringAndClear();
            pVCLPopupMenu->SetItemCommand( i+1, aFontNameCommand ); // Store font name into item command.
        }
    }
}

// XEventListener
void SAL_CALL FontMenuController::disposing( const EventObject& ) throw ( RuntimeException )
{
    Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );

    ResetableGuard aLock( m_aLock );
    m_xFrame.clear();
    m_xDispatch.clear();
    m_xFontListDispatch.clear();
    m_xServiceManager.clear();

    if ( m_xPopupMenu.is() )
        m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
    m_xPopupMenu.clear();
}

// XStatusListener
void SAL_CALL FontMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException )
{
    com::sun::star::awt::FontDescriptor aFontDescriptor;
    Sequence< rtl::OUString >           aFontNameSeq;

    if ( Event.State >>= aFontDescriptor )
    {
        ResetableGuard aLock( m_aLock );
        m_aFontFamilyName = aFontDescriptor.Name;
    }
    else if ( Event.State >>= aFontNameSeq )
    {
        ResetableGuard aLock( m_aLock );
        if ( m_xPopupMenu.is() )
            fillPopupMenu( aFontNameSeq, m_xPopupMenu );
    }
}

// XMenuListener
void SAL_CALL FontMenuController::highlight( const css::awt::MenuEvent& ) throw (RuntimeException)
{
}

void SAL_CALL FontMenuController::select( const css::awt::MenuEvent& rEvent ) throw (RuntimeException)
{
    Reference< css::awt::XPopupMenu >   xPopupMenu;
    Reference< XDispatch >              xDispatch;
    Reference< XMultiServiceFactory >   xServiceManager;

    ResetableGuard aLock( m_aLock );
    xPopupMenu      = m_xPopupMenu;
    xDispatch       = m_xDispatch;
    xServiceManager = m_xServiceManager;
    aLock.unlock();

    if ( xPopupMenu.is() && xDispatch.is() )
    {
        VCLXPopupMenu* pPopupMenu = (VCLXPopupMenu *)VCLXPopupMenu::GetImplementation( xPopupMenu );
        if ( pPopupMenu )
        {
            css::util::URL               aTargetURL;
            Sequence<PropertyValue>      aArgs;
            Reference< XURLTransformer > xURLTransformer( xServiceManager->createInstance(
                                                            rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
                                                        UNO_QUERY );

            {
                vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );

                // Command URL used to dispatch the selected font family name
                PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();
                aTargetURL.Complete = pVCLPopupMenu->GetItemCommand( rEvent.MenuId );
            }

            xURLTransformer->parseStrict( aTargetURL );
            xDispatch->dispatch( aTargetURL, aArgs );
        }
    }
}

void SAL_CALL FontMenuController::activate( const css::awt::MenuEvent& ) throw (RuntimeException)
{
    ResetableGuard aLock( m_aLock );

    if ( m_xPopupMenu.is() )
    {
        // find new font name and set check mark!
        USHORT        nChecked = 0;
        USHORT        nItemCount = m_xPopupMenu->getItemCount();
        rtl::OUString aEmpty;
        for( USHORT i = 0; i < nItemCount; i++ )
        {
            USHORT nItemId = m_xPopupMenu->getItemId( i );

            if ( m_xPopupMenu->isItemChecked( nItemId ) )
                nChecked = nItemId;

            rtl::OUString aText = m_xPopupMenu->getItemText( nItemId );

            // TODO: must be replaced by implementation of VCL, when available
            sal_Int32 nIndex = aText.indexOf( (sal_Unicode)'~' );
            if ( nIndex >= 0 )
                aText = aText.replaceAt( nIndex, 1, aEmpty );
            // TODO: must be replaced by implementation of VCL, when available

            if ( aText == m_aFontFamilyName )
            {
                m_xPopupMenu->checkItem( nItemId, sal_True );
                return;
            }
        }

        if ( nChecked )
            m_xPopupMenu->checkItem( nChecked, sal_False );
    }
}

void SAL_CALL FontMenuController::deactivate( const css::awt::MenuEvent& ) throw (RuntimeException)
{
}

// XPopupMenuController
void SAL_CALL FontMenuController::setPopupMenu( const Reference< css::awt::XPopupMenu >& xPopupMenu ) throw (RuntimeException)
{
    ResetableGuard aLock( m_aLock );

    if ( m_bDisposed )
        throw DisposedException();

    if ( m_xFrame.is() && !m_xPopupMenu.is() )
    {
        // Create popup menu on demand
        vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );

        m_xPopupMenu = xPopupMenu;
        m_xPopupMenu->addMenuListener( Reference< css::awt::XMenuListener >( (OWeakObject*)this, UNO_QUERY ));

        Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
                                                        rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
                                                    UNO_QUERY );
        Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );

        com::sun::star::util::URL aTargetURL;
        aTargetURL.Complete = m_aCommandURL;
        xURLTransformer->parseStrict( aTargetURL );
        m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );

        // Register for font list updates to get the current font list from the controller
        aTargetURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontNameList" ));
        xURLTransformer->parseStrict( aTargetURL );
        m_xFontListDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );

        updatePopupMenu();
    }
}

void SAL_CALL FontMenuController::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException )
{
    PopupMenuControllerBase::updatePopupMenu();

    ResetableGuard aLock( m_aLock );
    Reference< XDispatch > xDispatch( m_xFontListDispatch );
    Reference< XURLTransformer > xURLTransformer( m_xServiceManager->createInstance(
                                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
                                                UNO_QUERY );
    com::sun::star::util::URL aTargetURL;
    aTargetURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontNameList" ));
    xURLTransformer->parseStrict( aTargetURL );
    aLock.unlock();

    if ( xDispatch.is() )
    {
        xDispatch->addStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
        xDispatch->removeStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
    }
}

// XInitialization
void SAL_CALL FontMenuController::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException )
{
    PopupMenuControllerBase::initialize( aArguments );
}

}
<|endoftext|>


<commit_before>#include <iostream> //cout
#include <cstdlib>	//rand, sran
#include <string>
#include "complex_matrices.h"
#include <gmc.h> 	//LaGenMatComplex
#include <laslv.h>  //LUFactorizeIP, LaLUInverseIP, etc.
#include <blas3pp.h>

using namespace std;

/* Total [13/20] */

/* Printing [6/9] */
void print_scalar(const COMPLEX scalar){
    cout << scalar << endl;
}                                                 //working
void print_scalar(const COMPLEX scalar, const string name){
    cout << name << ":" << scalar << endl;
}                              //working
void print_array(const COMPLEX array[], int len){
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                                        //working
void print_array(const COMPLEX array[], int len, const string name){
	cout << name << ":" << endl;
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                     //working
void print_matrix(const LaGenMatComplex& matrix){
	cout << matrix << endl;
}                                        //working
void print_matrix(const LaGenMatComplex& matrix, const string name){
	cout << name << ":" << endl << matrix << endl;
}			          //working

/* Number generation [2/2] */
void generate_scalar(COMPLEX& A, const int x){
    A.r = rand() % x;	//1 to x
    A.i = rand() % x;
}                                           //working
void generate_scalar(int A, const int x){
    A = rand() % x;	//1 to x
}                                                //working
void generate_array(COMPLEX array[], const int len, const int x){
	srand(time(NULL));				//seed
    for(int i = 0; i < len; i++){
        array[i].r = rand() % x;	//1 to x
        array[i].i = rand() % x;
	}
}                        //working

/* Matrix conversion [3/3] */
void vec_to_array(const LaVectorComplex& vector, const int len, COMPLEX array[ ]){
    for(int i = 0; i < len; i++){
        array[i] = vector(i);
    }
}       //working
void array_to_diag(COMPLEX array[], const int len, LaGenMatComplex& diag){
    diag = 0;
    for(int i = 0; i < len; i++){
        diag(i, i) = array[i];
    }
}               //working
void vec_to_diag(const LaVectorComplex& vector, const int len, LaGenMatComplex& diag){
    COMPLEX array[len];
    vec_to_array(vector, len, array);
    array_to_diag(array, len, diag);
}   //working

/* Scalar manipulation [5/8] */
int factorial(int x){
	if(x <= 1){
        return 1;
	}else{
        return x * factorial(x - 1);
	}
}                                                                    //working
void scalar_addition(const COMPLEX& A, const COMPLEX& B , COMPLEX& result){
    result.r = A.r + B.r;
    result.i = A.i + B.i;
}              //working
void scalar_multiplication(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r * B;
    result.i = A.i * B;
}              //to test
void scalar_multiplication(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA * laB;
    result = laResult.toCOMPLEX();
}         //to test
void scalar_division(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r / B;
    result.i = A.i / B;
}                    //to test
void scalar_division(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA / laB;
    result = laResult.toCOMPLEX();
}               //to test
void scalar_powers(const COMPLEX& number, const int power, COMPLEX& result){
    la::complex<double> laResult = la::complex<double>(number);
    la::complex<double> laNumber = la::complex<double>(number);
    for(int i = 1; i < power; i++){
        laResult *= laNumber;
    }
    result = laResult.toCOMPLEX();
}             //to test
void scalar_exponential_1(const COMPLEX& number, const double step, const COMPLEX& result){
    double division, total_division = 1, result = 1;
    for(int n = 1; n <= iterations; n++){   //sum (from 1 to n)
        total_division = 1;
        for(int i = 1; i <= n; i++){        //    ( num^n / n!)
            scalar_division(number, i, division);     //
            scalar_multiplication(total_division, division, total_division);
        }
        scalar_addition(result, total_division, result)
    }
}
void scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    COMPLEX power;
    COMPLEX division;
    result.r = 0;
    result.i = 0;
    for(int i = 0; i < iter; i++){
        scalar_powers(number, i, power);
        scalar_division(power, factorial(i), division);
        scalar_addition(result, division)
    }
}         //empty
COMPLEX rec_scalar_exp_step(const COMPLEX& number, const int step){
	if(step <= 1){
        return 1;
	}else{
        return number / step * rec_scalar_exp_step(step-1);
	}
}
void recursive_scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    COMPLEX power;
    COMPLEX division;
    result.r = 0;
    result.i = 0;
    for(int i = 0; i < iter; i++){
        scalar_powers(number, i, power);
        scalar_division(power, factorial(i), division);
        scalar_addition(result, division)
    }
} //empty

/* array manipulation [0/1] */
void array_powers(COMPLEX array[], const int len, const int power){/**/
    /*
    for(int i = 0; i < len; i++){
        array[i] = complex_power(array[i], power, result);
    }
    */
}                       //empty

/* Matrix manipulation [2/4] */
void diagonal_matrix_powers(){      //empty
  ...
}
void matrix_eigenvstuff(const LaGenMatComplex& matrix, LaVectorComplex& eigenvalues, LaGenMatComplex& eigenvectors){ //working
    //LaEigSolve: http://lapackpp.sourceforge.net/html/laslv_8h.html#086357d17e9cdcaec69ab7db76998769
    LaEigSolve(matrix, eigenvalues, eigenvectors);
}
void matrix_inverse(LaGenMatComplex& matrix, int len){                                                               //working
    // LaLUInverseIP: http://lapackpp.sourceforge.net/html/laslv_8h.html#a042c82c5b818f54e7f000d068f14189
    LaVectorLongInt PIV = LaVectorLongInt(len);
    LUFactorizeIP(matrix, PIV);
    LaLUInverseIP(matrix, PIV);
}
void matrix_exp_step(){                                 //empty
    //
}
void matrix_exponential(const LaGenMatComplex& eigenvectors, const LaGenMatComplex& eigenvalues){
    //LaGenMatComplex step = LaGenMatComplex

} //empty

/* Testing [3/3] */
void test_scalar_manipulation(const int max_rand){
    COMPLEX compA;                                                              //initialisation
    generate_scalar(compA, max_rand);
    COMPLEX compB;
    generate_scalar(compB, max_rand);
    int realB;
    generate_scalar(realB, max_rand);
    COMPLEX result;

    for(int i = 1; i < 5; i++){                                                 //factorials
        cout << "factorial(" << i << "): " << factorial(i) << endl;
    }

    scalar_addition(compA, compB, result);                                      //addition/subtraction
    cout << "scalar addition: " << result << endl << endl;

    scalar_multiplication(compA, realB, result);                                //multiplication
    cout << "scalar multiplication by scalar: " << result << endl << endl;
    scalar_multiplication(compA, compB, result);
    cout << "scalar multiplication by complex: " << result << endl << endl;

    scalar_division(compA, realB, result);                                      //division
    cout << "scalar division by scalar: " << result << endl << endl;
    scalar_division(compA, compB, result);
    cout << "scalar division by complex: " << result << endl << endl;

    for(int i = 1; i < 5; i++){
        scalar_powers(compA, i, result);
        cout << "scalar powers - A^" << i << " = " << result << endl;
    }

}                                       //to test
void test_eigenvalues(const LaGenMatComplex& initialMatrix, const int size){
    LaVectorComplex eigenvalueVec = LaVectorComplex(size);             //initialise eigenstuff
    LaGenMatComplex eigenvalues = LaGenMatComplex::zeros(size, size);
    LaGenMatComplex eigenvectors = LaGenMatComplex::zeros(size, size);
    matrix_eigenvstuff(initialMatrix, eigenvalueVec, eigenvectors); //calculate eigenstuff
    print_matrix(eigenvalueVec, "eigenvalue vector");               //print eigenstuff
    vec_to_diag(eigenvalueVec, size, eigenvalues);
    print_matrix(eigenvalues, "eigenvalue matrix");
    print_matrix(eigenvectors, "eigenvector matrix");
}             //to test
void test_inverse(const LaGenMatComplex& initialMatrix, const int size){
    LaGenMatComplex inverseMatrix;
    inverseMatrix = initialMatrix.copy();
    matrix_inverse(inverseMatrix, size);
    print_matrix(inverseMatrix, "inverse matrix");
}                 //to test
void test_scalar_exponential(const int step){
    int max_rand = 9;
    COMPLEX number;
    generate_scalar(number, max_rand);
    cout << "scalar exponential test number : " << number << endl << endl;
    for(int i = 0; i < step; i++){
        cout << rec_scalar_exp_step(number, i) << endl;
    }

    //test accuracy
        for()

}
void test_matrix_exponential(const LaGenMatComplex& initialMatrix, const int size){

}
/* Main Program */
int main(){
    //m = matrix size, x = max
	int matrix_size = 3, max_rand = 9;
    int matrix_volume = matrix_size * matrix_size;

	/* generate the matrix */
    COMPLEX elements[matrix_volume];
    generate_array(elements, matrix_volume, max_rand);
	LaGenMatComplex initialMatrix = LaGenMatComplex(elements, matrix_size, matrix_size, false );

    print_matrix(initialMatrix, "initial matrix");

    /* test eigenvalues */
    test_eigenvalues(initialMatrix, matrix_size);

    /* test scalar manipulation */
    test_scalar_manipulation(max_rand);

    /* test scalar exponentials */
    test_scalar_exponential(10);

    /* test inversion */
    test_inverse(initialMatrix, matrix_size);
}
<commit_msg>testing<commit_after>#include <iostream> //cout
#include <cstdlib>	//rand, sran
#include <string>
#include "complex_matrices.h"
#include <gmc.h> 	//LaGenMatComplex
#include <laslv.h>  //LUFactorizeIP, LaLUInverseIP, etc.
#include <blas3pp.h>

using namespace std;

/* Total [13/20] */

/* Printing [6/9] */
void print_scalar(const COMPLEX scalar){
    cout << scalar << endl;
}                                                 //working
void print_scalar(const COMPLEX scalar, const string name){
    cout << name << ":" << scalar << endl;
}                              //working
void print_array(const COMPLEX array[], int len){
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                                        //working
void print_array(const COMPLEX array[], int len, const string name){
	cout << name << ":" << endl;
    for(int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
}                     //working
void print_matrix(const LaGenMatComplex& matrix){
	cout << matrix << endl;
}                                        //working
void print_matrix(const LaGenMatComplex& matrix, const string name){
	cout << name << ":" << endl << matrix << endl;
}			          //working

/* Number generation [2/2] */
void generate_scalar(COMPLEX& A, const int x){
    A.r = rand() % x;	//1 to x
    A.i = rand() % x;
}                                           //working
void generate_scalar(int A, const int x){
    A = rand() % x;	//1 to x
}                                                //working
void generate_array(COMPLEX array[], const int len, const int x){
	srand(time(NULL));				//seed
    for(int i = 0; i < len; i++){
        array[i].r = rand() % x;	//1 to x
        array[i].i = rand() % x;
	}
}                        //working

/* Matrix conversion [3/3] */
void vec_to_array(const LaVectorComplex& vector, const int len, COMPLEX array[ ]){
    for(int i = 0; i < len; i++){
        array[i] = vector(i);
    }
}       //working
void array_to_diag(COMPLEX array[], const int len, LaGenMatComplex& diag){
    diag = 0;
    for(int i = 0; i < len; i++){
        diag(i, i) = array[i];
    }
}               //working
void vec_to_diag(const LaVectorComplex& vector, const int len, LaGenMatComplex& diag){
    COMPLEX array[len];
    vec_to_array(vector, len, array);
    array_to_diag(array, len, diag);
}   //working

/* Scalar manipulation [5/8] */
int factorial(int x){
	if(x <= 1){
        return 1;
	}else{
        return x * factorial(x - 1);
	}
}                                                                    //working
void scalar_addition(const COMPLEX& A, const COMPLEX& B , COMPLEX& result){
    result.r = A.r + B.r;
    result.i = A.i + B.i;
}              //working
void scalar_multiplication(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r * B;
    result.i = A.i * B;
}              //to test
void scalar_multiplication(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA * laB;
    result = laResult.toCOMPLEX();
}         //to test
void scalar_division(const COMPLEX& A, const int B, COMPLEX& result){
    result.r = A.r / B;
    result.i = A.i / B;
}                    //to test
void scalar_division(const COMPLEX& A, const COMPLEX& B, COMPLEX& result){
    la::complex<double> laA = la::complex<double>(A); //convert to la::complex<double>
    la::complex<double> laB = la::complex<double>(B);
    la::complex<double> laResult = la::complex<double>(result);
    laResult = laA / laB;
    result = laResult.toCOMPLEX();
}               //to test
void scalar_powers(const COMPLEX& number, const int power, COMPLEX& result){
    la::complex<double> laResult = la::complex<double>(number);
    la::complex<double> laNumber = la::complex<double>(number);
    for(int i = 1; i < power; i++){
        laResult *= laNumber;
    }
    result = laResult.toCOMPLEX();
}             //to test
void scalar_exponential_1(const COMPLEX& number, const int iterations, const COMPLEX& result){
    COMPLEX division, total_division = 1;
    result.r = 1;
    result.i = 1;
    const int step;
    for(int step = 1; step <= iterations; step++){   //sum (from 1 to n)
        for(int i = 1; i <= step; i++){        //    ( num^n / n!)
            scalar_division(number, i, division);     //
            scalar_multiplication(total_division, division, total_division);
        }
        scalar_addition(result, total_division, result)
    }
}
void scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    COMPLEX power;
    COMPLEX division;
    result.r = 0;
    result.i = 0;
    for(int i = 0; i < iter; i++){
        scalar_powers(number, i, power);
        scalar_division(power, factorial(i), division);
        scalar_addition(result, division)
    }
}         //empty
COMPLEX rec_scalar_exp_step(const COMPLEX& number, const int step){
	if(step <= 1){
        return 1;
	}else{
        return number / step * rec_scalar_exp_step(step-1);
	}
}
void recursive_scalar_exponential(const COMPLEX& number, const int iter, COMPLEX& result){
    COMPLEX power;
    COMPLEX division;
    result.r = 0;
    result.i = 0;
    for(int i = 0; i < iter; i++){
        scalar_powers(number, i, power);
        scalar_division(power, factorial(i), division);
        scalar_addition(result, division)
    }
} //empty

/* array manipulation [0/1] */
void array_powers(COMPLEX array[], const int len, const int power){/**/
    /*
    for(int i = 0; i < len; i++){
        array[i] = complex_power(array[i], power, result);
    }
    */
}                       //empty

/* Matrix manipulation [2/4] */
void diagonal_matrix_powers(){      //empty
  ...
}
void matrix_eigenvstuff(const LaGenMatComplex& matrix, LaVectorComplex& eigenvalues, LaGenMatComplex& eigenvectors){ //working
    //LaEigSolve: http://lapackpp.sourceforge.net/html/laslv_8h.html#086357d17e9cdcaec69ab7db76998769
    LaEigSolve(matrix, eigenvalues, eigenvectors);
}
void matrix_inverse(LaGenMatComplex& matrix, int len){                                                               //working
    // LaLUInverseIP: http://lapackpp.sourceforge.net/html/laslv_8h.html#a042c82c5b818f54e7f000d068f14189
    LaVectorLongInt PIV = LaVectorLongInt(len);
    LUFactorizeIP(matrix, PIV);
    LaLUInverseIP(matrix, PIV);
}
void matrix_exp_step(){                                 //empty
    //
}
void matrix_exponential(const LaGenMatComplex& eigenvectors, const LaGenMatComplex& eigenvalues){
    //LaGenMatComplex step = LaGenMatComplex

} //empty

/* Testing [3/3] */
void test_scalar_manipulation(const int max_rand){
    COMPLEX compA;                                                              //initialisation
    generate_scalar(compA, max_rand);
    COMPLEX compB;
    generate_scalar(compB, max_rand);
    int realB;
    generate_scalar(realB, max_rand);
    COMPLEX result;

    for(int i = 1; i < 5; i++){                                                 //factorials
        cout << "factorial(" << i << "): " << factorial(i) << endl;
    }

    scalar_addition(compA, compB, result);                                      //addition/subtraction
    cout << "scalar addition: " << result << endl << endl;

    scalar_multiplication(compA, realB, result);                                //multiplication
    cout << "scalar multiplication by scalar: " << result << endl << endl;
    scalar_multiplication(compA, compB, result);
    cout << "scalar multiplication by complex: " << result << endl << endl;

    scalar_division(compA, realB, result);                                      //division
    cout << "scalar division by scalar: " << result << endl << endl;
    scalar_division(compA, compB, result);
    cout << "scalar division by complex: " << result << endl << endl;

    for(int i = 1; i < 5; i++){
        scalar_powers(compA, i, result);
        cout << "scalar powers - A^" << i << " = " << result << endl;
    }

}                                       //to test
void test_eigenvalues(const LaGenMatComplex& initialMatrix, const int size){
    LaVectorComplex eigenvalueVec = LaVectorComplex(size);             //initialise eigenstuff
    LaGenMatComplex eigenvalues = LaGenMatComplex::zeros(size, size);
    LaGenMatComplex eigenvectors = LaGenMatComplex::zeros(size, size);
    matrix_eigenvstuff(initialMatrix, eigenvalueVec, eigenvectors); //calculate eigenstuff
    print_matrix(eigenvalueVec, "eigenvalue vector");               //print eigenstuff
    vec_to_diag(eigenvalueVec, size, eigenvalues);
    print_matrix(eigenvalues, "eigenvalue matrix");
    print_matrix(eigenvectors, "eigenvector matrix");
}             //to test
void test_inverse(const LaGenMatComplex& initialMatrix, const int size){
    LaGenMatComplex inverseMatrix;
    inverseMatrix = initialMatrix.copy();
    matrix_inverse(inverseMatrix, size);
    print_matrix(inverseMatrix, "inverse matrix");
}                 //to test
void test_scalar_exponential(const int step){
    int max_rand = 9;
    COMPLEX number;
    generate_scalar(number, max_rand);
    cout << "scalar exponential test number : " << number << endl << endl;
    for(int i = 0; i < step; i++){
        cout << rec_scalar_exp_step(number, i) << endl;
    }

    //test accuracy
        for()

}
void test_matrix_exponential(const LaGenMatComplex& initialMatrix, const int size){

}
/* Main Program */
int main(){
    //m = matrix size, x = max
	int matrix_size = 3, max_rand = 9;
    int matrix_volume = matrix_size * matrix_size;

	/* generate the matrix */
    COMPLEX elements[matrix_volume];
    generate_array(elements, matrix_volume, max_rand);
	LaGenMatComplex initialMatrix = LaGenMatComplex(elements, matrix_size, matrix_size, false );

    print_matrix(initialMatrix, "initial matrix");

    /* test eigenvalues */
    test_eigenvalues(initialMatrix, matrix_size);

    /* test scalar manipulation */
    test_scalar_manipulation(max_rand);

    /* test scalar exponentials */
    test_scalar_exponential(10);

    /* test inversion */
    test_inverse(initialMatrix, matrix_size);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, 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 "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	anonymous_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
};

void test_proxy(proxy_settings::proxy_type proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & anonymous_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = g_udp_tracker_requests;
	int prev_http_announces = g_http_tracker_requests;

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.stop_tracker_timeout = 1;
	sett.tracker_completion_timeout = 1;
	sett.tracker_receive_timeout = 1;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	sett.anonymous_mode = flags & anonymous_mode;
	sett.force_proxy = flags & anonymous_mode;

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.enable_outgoing_utp = false;
	s->set_settings(sett);

	proxy_settings ps;
	ps.hostname = "non-existing.com";
	ps.port = 4444;
	ps.type = proxy_type;
	s->set_proxy(ps);

	s->start_dht();

	error_code ec;
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();
	for (int i = 0; i < 15; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (g_udp_tracker_requests >= prev_udp_announces + 1
			&& g_http_tracker_requests >= prev_http_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + bool(flags & expect_udp_connection));
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + bool(flags & expect_http_connection));
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	delete s;
	fprintf(stderr, "%s: ~session done\n", time_now_string());

	stop_peer();
	stop_dht();
	stop_tracker();
	stop_web_server();
}

int test_main()
{
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	test_proxy(proxy_settings::socks4, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	test_proxy(proxy_settings::none, anonymous_mode | expect_peer_connection);
	test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::socks5, anonymous_mode);
	test_proxy(proxy_settings::socks5_pw, anonymous_mode);
	test_proxy(proxy_settings::http, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::http_pw, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::i2p_proxy, anonymous_mode);
	return 0;
}

<commit_msg>increase tracker timeouts for test_privacy<commit_after>/*

Copyright (c) 2013, 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 "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	anonymous_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
};

void test_proxy(proxy_settings::proxy_type proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & anonymous_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = g_udp_tracker_requests;
	int prev_http_announces = g_http_tracker_requests;

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.stop_tracker_timeout = 2;
	sett.tracker_completion_timeout = 2;
	sett.tracker_receive_timeout = 2;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	sett.anonymous_mode = flags & anonymous_mode;
	sett.force_proxy = flags & anonymous_mode;

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.enable_outgoing_utp = false;
	s->set_settings(sett);

	proxy_settings ps;
	ps.hostname = "non-existing.com";
	ps.port = 4444;
	ps.type = proxy_type;
	s->set_proxy(ps);

	s->start_dht();

	error_code ec;
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();
	for (int i = 0; i < 15; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (g_udp_tracker_requests >= prev_udp_announces + 1
			&& g_http_tracker_requests >= prev_http_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + bool(flags & expect_udp_connection));
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + bool(flags & expect_http_connection));
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	delete s;
	fprintf(stderr, "%s: ~session done\n", time_now_string());

	stop_peer();
	stop_dht();
	stop_tracker();
	stop_web_server();
}

int test_main()
{
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	test_proxy(proxy_settings::socks4, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	test_proxy(proxy_settings::none, anonymous_mode | expect_peer_connection);
	test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::socks5, anonymous_mode);
	test_proxy(proxy_settings::socks5_pw, anonymous_mode);
	test_proxy(proxy_settings::http, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::http_pw, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::i2p_proxy, anonymous_mode);
	return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2015-present, Qihoo, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
#include "pink/include/http_conn.h"
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>

#include <string>
#include <algorithm>

#include "slash/include/xdebug.h"
#include "slash/include/slash_string.h"
#include "pink/include/pink_define.h"
#include "pink/src/worker_thread.h"

namespace pink {

static const uint32_t kHttpMaxMessage = 1024 * 1024 * 8;
static const uint32_t kHttpMaxHeader = 1024 * 64;

static const std::map<int, std::string> http_status_map = {
  {100, "Continue"},
  {101, "Switching Protocols"},
  {102, "Processing"},

  {200, "OK"},
  {201, "Created"},
  {202, "Accepted"},
  {203, "Non-Authoritative Information"},
  {204, "No Content"},
  {205, "Reset Content"},
  {206, "Partial Content"},
  {207, "Multi-Status"},

  {400, "Bad Request"},
  {401, "Unauthorized"},
  {402, ""},  // reserve
  {403, "Forbidden"},
  {404, "Not Found"},
  {405, "Method Not Allowed"},
  {406, "Not Acceptable"},
  {407, "Proxy Authentication Required"},
  {408, "Request Timeout"},
  {409, "Conflict"},
  {416, "Requested Range not satisfiable"},

  {500, "Internal Server Error"},
  {501, "Not Implemented"},
  {502, "Bad Gateway"},
  {503, "Service Unavailable"},
  {504, "Gateway Timeout"},
  {505, "HTTP Version Not Supported"},
  {506, "Variant Also Negotiates"},
  {507, "Insufficient Storage"},
  {508, "Bandwidth Limit Exceeded"},
  {509, "Not Extended"},
};

HttpRequest::HttpRequest():
  method("GET"),
  path("/index") {
}

inline int find_lf(const char* data, int size) {
  const char* c = data;
  int count = 0;
  while (count < size) {
    if (*c == '\n') {
      break;
    }
    c++;
    count++;
  }
  return count;
}

bool HttpRequest::ParseHeadLine(const char* data, int line_start,
    int line_end, ParseStatus* parseStatus) {
  std::string param_key;
  std::string param_value;
  for (int i = line_start; i <= line_end; i++) {
    switch (*parseStatus) {
      case kHeaderMethod:
        if (data[i] != ' ') {
          method.push_back(data[i]);
        } else {
          *parseStatus = kHeaderPath;
        }
        break;
      case kHeaderPath:
        if (data[i] != ' ') {
          path.push_back(data[i]);
        } else {
          *parseStatus = kHeaderVersion;
        }
        break;
      case kHeaderVersion:
        if (data[i] != '\r' && data[i] != '\n') {
          version.push_back(data[i]);
        } else if (data[i] == '\n') {
          *parseStatus = kHeaderParamKey;
        }
        break;
      case kHeaderParamKey:
        if (data[i] != ':' && data[i] != ' ') {
          param_key.push_back(data[i]);
        } else if (data[i] == ' ') {
          *parseStatus = kHeaderParamValue;
        }
        break;
      case kHeaderParamValue:
        if (data[i] != '\r' && data[i] != '\n') {
          param_value.push_back(data[i]);
        } else if (data[i] == '\r') {
          headers[slash::StringToLower(param_key)] = param_value;
          *parseStatus = kHeaderParamKey;
        }
        break;

      default:
        return false;
    }
  }
  return true;
}

bool HttpRequest::ParseGetUrl() {
  // Format path
  if (path.find(headers["host"]) != std::string::npos &&
      path.size() > (7 + headers["host"].size())) {
    // http://www.xxx.xxx/path/to
    path.assign(path.substr(7 + headers["host"].size()));
  }
  size_t n = path.find('?');
  if (n == std::string::npos) {
    return true; // no parameter
  }
  if (!ParseParameters(path, n + 1)) {
    return false;
  }
  path.resize(n);
  return true;
}

// Parse query parameter from GET url or POST body
// format: key1=value1&key2=value2&key3=value3
bool HttpRequest::ParseParameters(const std::string data,
    size_t line_start) {
  size_t pre = line_start, mid, end;
  while (pre < data.size()) {
    mid = data.find('=', pre);
    if (mid == std::string::npos) {
      mid = data.size();
    }
    end = data.find('&', pre);
    if (end == std::string::npos) {
      end = data.size();
    }
    if (end <= mid) {
      // empty value
      query_params[data.substr(pre, end - pre)]
        = std::string();
      pre = end + 1;
    } else {
      query_params[data.substr(pre, mid - pre)]
        = data.substr(mid + 1, end - mid - 1);
      pre = end + 1;
    }
  }
  return true;
}

bool HttpRequest::ParseHeadFromArray(const char* data, const int size) {
  int remain_size = size;
  if (remain_size <= 5) {
    return false;
  }

  // Parse header line
  int line_start = 0;
  int line_end = 0;
  ParseStatus parseStatus = kHeaderMethod;
  while (remain_size > 4) {
    line_end += find_lf(data + line_start, remain_size);
    if (line_end < line_start) {
      return false;
    }
    if (!ParseHeadLine(data, line_start, line_end, &parseStatus)) {
      return false;
    }
    remain_size -= (line_end - line_start + 1);
    line_start = ++line_end;
  }

  // Parse query parameter from url
  if (!ParseGetUrl()) {
    return false;
  }
  return true;
}

bool HttpRequest::ParseBodyFromArray(const char* data, const int size) {
  content.append(data, size);
  // if (method == "POST") {
  //   return ParseParameters(content);
  // }
  return true;
}

void HttpRequest::Clear() {
  version.clear();
  path.clear();
  method.clear();
  query_params.clear();
  headers.clear();
  content.clear();
}

void HttpResponse::Clear() {
  status_code_ = 0;
  reason_phrase_.clear();
  headers_.clear();
  body_.clear();
}

// Return bytes actual be writen, should be less than size
int HttpResponse::SerializeHeaderToArray(char* data, size_t size) {
  int serial_size = 0;
  int ret;

  // Serialize statues line
  ret = snprintf(data, size, "HTTP/1.1 %d %s\r\n",
                 status_code_, reason_phrase_.c_str());
  if (ret < 0 || ret == static_cast<int>(size)) {
    return ret;
  }
  serial_size += ret;

  // Serialize header
  SetHeaders("Content-Length", body_.size());
  for (auto &line : headers_) {
    ret = snprintf(data + serial_size, size - serial_size, "%s: %s\r\n",
                   line.first.c_str(), line.second.c_str());
    if (ret < 0) {
      return ret;
    }
    serial_size += ret;
    if (serial_size == static_cast<int>(size)) {
      return serial_size;
    }
  }

  ret = snprintf(data + serial_size, size - serial_size, "\r\n");
  serial_size += ret;
  return serial_size;
}

// Serialize body begin from 'pos', return the new pos
int HttpResponse::SerializeBodyToArray(char* data, size_t size, int* pos) {
  // Serialize body
  int actual = size;
  if (body_.size() - *pos < size) {
    actual = body_.size() - *pos;
  }
  memcpy(data, body_.data() + *pos, actual);
  *pos += actual;
  return actual;
}

void HttpResponse::SetStatusCode(int code) {
  assert((code >= 100 && code <= 102) ||
         (code >= 200 && code <= 207) ||
         (code >= 400 && code <= 409) ||
         (code == 416) ||
         (code >= 500 && code <= 509));
  status_code_ = code;
  reason_phrase_.assign(http_status_map.at(code));
}

HttpConn::HttpConn(const int fd, const std::string &ip_port,  Thread *thread) :
  PinkConn(fd, ip_port, thread),
  conn_status_(kHeader),
  rbuf_pos_(0),
  wbuf_len_(0),
  wbuf_pos_(0),
  header_len_(0),
  remain_packet_len_(0),
  response_pos_(-1) {
  rbuf_ = (char *)malloc(sizeof(char) * kHttpMaxMessage);
  wbuf_ = (char *)malloc(sizeof(char) * kHttpMaxMessage);
  request_ = new HttpRequest();
  response_ = new HttpResponse();
}

HttpConn::~HttpConn() {
  free(rbuf_);
  free(wbuf_);
  delete request_;
  delete response_;
}

/*
 * Build request_
 */
bool HttpConn::BuildRequestHeader() {
  request_->Clear();
  if (!request_->ParseHeadFromArray(rbuf_, header_len_)) {
    return false;
  }
  auto iter = request_->headers.begin();
  iter = request_->headers.find("content-length");
  if (iter == request_->headers.end()) {
    remain_packet_len_ = 0;
  } else {
    int64_t tmp = 0;
    slash::string2l(iter->second.data(), iter->second.size(),
        static_cast<long*>(&tmp));
    remain_packet_len_ = tmp;
  }

  if (rbuf_pos_ > header_len_) {
    remain_packet_len_ -= rbuf_pos_ - header_len_;
  }
  return true;
}

bool HttpConn::AppendRequestBody() {
  return request_->ParseBodyFromArray(rbuf_ + header_len_,
      rbuf_pos_  - header_len_);
}

void HttpConn::HandleMessage() {
  response_->Clear();
  DealMessage(request_, response_);
  set_is_reply(true);
}

ReadStatus HttpConn::GetRequest() {
  ssize_t nread = 0;
  while (true) {
    switch (conn_status_) {
      case kHeader: {
        nread = read(fd(), rbuf_ + rbuf_pos_, kHttpMaxHeader - rbuf_pos_);
        if (nread == -1 && errno == EAGAIN) {
          return kReadHalf;
        } else if (nread <= 0) {
          return kReadClose;
        } else {
          rbuf_pos_ += nread;
          rbuf_[rbuf_pos_] = '\0'; // So that strstr will not parse the expire char
          char *sep_pos = strstr(rbuf_, "\r\n\r\n");
          if (!sep_pos) {
            break;
          }
          header_len_ = sep_pos - rbuf_ + 4;
          if (!BuildRequestHeader()) {
            return kReadError;
          }
          conn_status_ = kPacket;
        }
        break;
      }
      case kPacket: {
        if (remain_packet_len_ > 0) {
          nread = read(fd(), rbuf_ + rbuf_pos_,
              (kHttpMaxMessage - rbuf_pos_ > remain_packet_len_)
              ? remain_packet_len_ : kHttpMaxMessage - rbuf_pos_);
          if (nread == -1 && errno == EAGAIN) {
            return kReadHalf;
          } else if (nread <= 0) {
            return kReadClose;
          } else {
            rbuf_pos_ += nread;
            remain_packet_len_ -= nread;
          }
        }
        if (remain_packet_len_ == 0 || // no more content
            rbuf_pos_ == kHttpMaxMessage) { // buffer full
          AppendRequestBody();
          if (remain_packet_len_ == 0) {
            conn_status_ = kComplete;
          } else {
            rbuf_pos_ = header_len_ = 0; // read more packet content from begin
          }
        }
        break;
      }
      case kComplete: {
        HandleMessage();
        conn_status_ = kHeader;
        rbuf_pos_ = 0;
        return kReadAll;
      }
      default: {
        return kReadError;
      }
    }
    // else continue
  }
}

bool HttpConn::FillResponseBuf() {
  if (response_pos_ < 0) {
    // Not ever serialize response header
    int actual = response_->SerializeHeaderToArray(wbuf_ + wbuf_len_,
        kHttpMaxMessage - wbuf_len_);
    if (actual < 0) {
      return false;
    }
    wbuf_len_ += actual;
    response_pos_ = 0; // Serialize body next time
  }
  while (response_->HasMoreBody(response_pos_)
      && wbuf_len_ < kHttpMaxMessage) {
    // Has more body and more space in wbuf_
    wbuf_len_ += response_->SerializeBodyToArray(wbuf_ + wbuf_len_,
        kHttpMaxMessage - wbuf_len_, &response_pos_);
  }
  return true;
}

WriteStatus HttpConn::SendReply() {
  // Fill as more as content into the buf
  if (!FillResponseBuf()) {
    return kWriteError;
  }

  ssize_t nwritten = 0;
  while (wbuf_len_ > 0) {
    nwritten = write(fd(), wbuf_ + wbuf_pos_, wbuf_len_ - wbuf_pos_);
    if (nwritten == -1 && errno == EAGAIN) {
      return kWriteHalf;
    } else if (nwritten <= 0) {
      return kWriteError;
    }
    wbuf_pos_ += nwritten;
    if (wbuf_pos_ == wbuf_len_) {
      // Send all in wbuf_ and Try to fill more
      wbuf_len_ = 0;
      wbuf_pos_ = 0;
      if (!FillResponseBuf()) {
        return kWriteError;
      }
    }
  }
  response_pos_ = -1; // fill header first next time

  return kWriteAll;
}

}  // namespace pink
<commit_msg>Allow Modify Content-Length<commit_after>// Copyright (c) 2015-present, Qihoo, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
#include "pink/include/http_conn.h"
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>

#include <string>
#include <algorithm>

#include "slash/include/xdebug.h"
#include "slash/include/slash_string.h"
#include "pink/include/pink_define.h"
#include "pink/src/worker_thread.h"

namespace pink {

static const uint32_t kHttpMaxMessage = 1024 * 1024 * 8;
static const uint32_t kHttpMaxHeader = 1024 * 64;

static const std::map<int, std::string> http_status_map = {
  {100, "Continue"},
  {101, "Switching Protocols"},
  {102, "Processing"},

  {200, "OK"},
  {201, "Created"},
  {202, "Accepted"},
  {203, "Non-Authoritative Information"},
  {204, "No Content"},
  {205, "Reset Content"},
  {206, "Partial Content"},
  {207, "Multi-Status"},

  {400, "Bad Request"},
  {401, "Unauthorized"},
  {402, ""},  // reserve
  {403, "Forbidden"},
  {404, "Not Found"},
  {405, "Method Not Allowed"},
  {406, "Not Acceptable"},
  {407, "Proxy Authentication Required"},
  {408, "Request Timeout"},
  {409, "Conflict"},
  {416, "Requested Range not satisfiable"},

  {500, "Internal Server Error"},
  {501, "Not Implemented"},
  {502, "Bad Gateway"},
  {503, "Service Unavailable"},
  {504, "Gateway Timeout"},
  {505, "HTTP Version Not Supported"},
  {506, "Variant Also Negotiates"},
  {507, "Insufficient Storage"},
  {508, "Bandwidth Limit Exceeded"},
  {509, "Not Extended"},
};

HttpRequest::HttpRequest():
  method("GET"),
  path("/index") {
}

inline int find_lf(const char* data, int size) {
  const char* c = data;
  int count = 0;
  while (count < size) {
    if (*c == '\n') {
      break;
    }
    c++;
    count++;
  }
  return count;
}

bool HttpRequest::ParseHeadLine(const char* data, int line_start,
    int line_end, ParseStatus* parseStatus) {
  std::string param_key;
  std::string param_value;
  for (int i = line_start; i <= line_end; i++) {
    switch (*parseStatus) {
      case kHeaderMethod:
        if (data[i] != ' ') {
          method.push_back(data[i]);
        } else {
          *parseStatus = kHeaderPath;
        }
        break;
      case kHeaderPath:
        if (data[i] != ' ') {
          path.push_back(data[i]);
        } else {
          *parseStatus = kHeaderVersion;
        }
        break;
      case kHeaderVersion:
        if (data[i] != '\r' && data[i] != '\n') {
          version.push_back(data[i]);
        } else if (data[i] == '\n') {
          *parseStatus = kHeaderParamKey;
        }
        break;
      case kHeaderParamKey:
        if (data[i] != ':' && data[i] != ' ') {
          param_key.push_back(data[i]);
        } else if (data[i] == ' ') {
          *parseStatus = kHeaderParamValue;
        }
        break;
      case kHeaderParamValue:
        if (data[i] != '\r' && data[i] != '\n') {
          param_value.push_back(data[i]);
        } else if (data[i] == '\r') {
          headers[slash::StringToLower(param_key)] = param_value;
          *parseStatus = kHeaderParamKey;
        }
        break;

      default:
        return false;
    }
  }
  return true;
}

bool HttpRequest::ParseGetUrl() {
  // Format path
  if (path.find(headers["host"]) != std::string::npos &&
      path.size() > (7 + headers["host"].size())) {
    // http://www.xxx.xxx/path/to
    path.assign(path.substr(7 + headers["host"].size()));
  }
  size_t n = path.find('?');
  if (n == std::string::npos) {
    return true; // no parameter
  }
  if (!ParseParameters(path, n + 1)) {
    return false;
  }
  path.resize(n);
  return true;
}

// Parse query parameter from GET url or POST body
// format: key1=value1&key2=value2&key3=value3
bool HttpRequest::ParseParameters(const std::string data,
    size_t line_start) {
  size_t pre = line_start, mid, end;
  while (pre < data.size()) {
    mid = data.find('=', pre);
    if (mid == std::string::npos) {
      mid = data.size();
    }
    end = data.find('&', pre);
    if (end == std::string::npos) {
      end = data.size();
    }
    if (end <= mid) {
      // empty value
      query_params[data.substr(pre, end - pre)]
        = std::string();
      pre = end + 1;
    } else {
      query_params[data.substr(pre, mid - pre)]
        = data.substr(mid + 1, end - mid - 1);
      pre = end + 1;
    }
  }
  return true;
}

bool HttpRequest::ParseHeadFromArray(const char* data, const int size) {
  int remain_size = size;
  if (remain_size <= 5) {
    return false;
  }

  // Parse header line
  int line_start = 0;
  int line_end = 0;
  ParseStatus parseStatus = kHeaderMethod;
  while (remain_size > 4) {
    line_end += find_lf(data + line_start, remain_size);
    if (line_end < line_start) {
      return false;
    }
    if (!ParseHeadLine(data, line_start, line_end, &parseStatus)) {
      return false;
    }
    remain_size -= (line_end - line_start + 1);
    line_start = ++line_end;
  }

  // Parse query parameter from url
  if (!ParseGetUrl()) {
    return false;
  }
  return true;
}

bool HttpRequest::ParseBodyFromArray(const char* data, const int size) {
  content.append(data, size);
  // if (method == "POST") {
  //   return ParseParameters(content);
  // }
  return true;
}

void HttpRequest::Clear() {
  version.clear();
  path.clear();
  method.clear();
  query_params.clear();
  headers.clear();
  content.clear();
}

void HttpResponse::Clear() {
  status_code_ = 0;
  reason_phrase_.clear();
  headers_.clear();
  body_.clear();
}

// Return bytes actual be writen, should be less than size
int HttpResponse::SerializeHeaderToArray(char* data, size_t size) {
  int serial_size = 0;
  int ret;

  // Serialize statues line
  ret = snprintf(data, size, "HTTP/1.1 %d %s\r\n",
                 status_code_, reason_phrase_.c_str());
  if (ret < 0 || ret == static_cast<int>(size)) {
    return ret;
  }
  serial_size += ret;

  // Serialize header
  if (headers_.find("Content-Length") == headers_.end()) {
    SetHeaders("Content-Length", body_.size());
  }
  for (auto &line : headers_) {
    ret = snprintf(data + serial_size, size - serial_size, "%s: %s\r\n",
                   line.first.c_str(), line.second.c_str());
    if (ret < 0) {
      return ret;
    }
    serial_size += ret;
    if (serial_size == static_cast<int>(size)) {
      return serial_size;
    }
  }

  ret = snprintf(data + serial_size, size - serial_size, "\r\n");
  serial_size += ret;
  return serial_size;
}

// Serialize body begin from 'pos', return the new pos
int HttpResponse::SerializeBodyToArray(char* data, size_t size, int* pos) {
  // Serialize body
  int actual = size;
  if (body_.size() - *pos < size) {
    actual = body_.size() - *pos;
  }
  memcpy(data, body_.data() + *pos, actual);
  *pos += actual;
  return actual;
}

void HttpResponse::SetStatusCode(int code) {
  assert((code >= 100 && code <= 102) ||
         (code >= 200 && code <= 207) ||
         (code >= 400 && code <= 409) ||
         (code == 416) ||
         (code >= 500 && code <= 509));
  status_code_ = code;
  reason_phrase_.assign(http_status_map.at(code));
}

HttpConn::HttpConn(const int fd, const std::string &ip_port,  Thread *thread) :
  PinkConn(fd, ip_port, thread),
  conn_status_(kHeader),
  rbuf_pos_(0),
  wbuf_len_(0),
  wbuf_pos_(0),
  header_len_(0),
  remain_packet_len_(0),
  response_pos_(-1) {
  rbuf_ = (char *)malloc(sizeof(char) * kHttpMaxMessage);
  wbuf_ = (char *)malloc(sizeof(char) * kHttpMaxMessage);
  request_ = new HttpRequest();
  response_ = new HttpResponse();
}

HttpConn::~HttpConn() {
  free(rbuf_);
  free(wbuf_);
  delete request_;
  delete response_;
}

/*
 * Build request_
 */
bool HttpConn::BuildRequestHeader() {
  request_->Clear();
  if (!request_->ParseHeadFromArray(rbuf_, header_len_)) {
    return false;
  }
  auto iter = request_->headers.begin();
  iter = request_->headers.find("content-length");
  if (iter == request_->headers.end()) {
    remain_packet_len_ = 0;
  } else {
    int64_t tmp = 0;
    slash::string2l(iter->second.data(), iter->second.size(),
        static_cast<long*>(&tmp));
    remain_packet_len_ = tmp;
  }

  if (rbuf_pos_ > header_len_) {
    remain_packet_len_ -= rbuf_pos_ - header_len_;
  }
  return true;
}

bool HttpConn::AppendRequestBody() {
  return request_->ParseBodyFromArray(rbuf_ + header_len_,
      rbuf_pos_  - header_len_);
}

void HttpConn::HandleMessage() {
  response_->Clear();
  DealMessage(request_, response_);
  set_is_reply(true);
}

ReadStatus HttpConn::GetRequest() {
  ssize_t nread = 0;
  while (true) {
    switch (conn_status_) {
      case kHeader: {
        nread = read(fd(), rbuf_ + rbuf_pos_, kHttpMaxHeader - rbuf_pos_);
        if (nread == -1 && errno == EAGAIN) {
          return kReadHalf;
        } else if (nread <= 0) {
          return kReadClose;
        } else {
          rbuf_pos_ += nread;
          rbuf_[rbuf_pos_] = '\0'; // So that strstr will not parse the expire char
          char *sep_pos = strstr(rbuf_, "\r\n\r\n");
          if (!sep_pos) {
            break;
          }
          header_len_ = sep_pos - rbuf_ + 4;
          if (!BuildRequestHeader()) {
            return kReadError;
          }
          conn_status_ = kPacket;
        }
        break;
      }
      case kPacket: {
        if (remain_packet_len_ > 0) {
          nread = read(fd(), rbuf_ + rbuf_pos_,
              (kHttpMaxMessage - rbuf_pos_ > remain_packet_len_)
              ? remain_packet_len_ : kHttpMaxMessage - rbuf_pos_);
          if (nread == -1 && errno == EAGAIN) {
            return kReadHalf;
          } else if (nread <= 0) {
            return kReadClose;
          } else {
            rbuf_pos_ += nread;
            remain_packet_len_ -= nread;
          }
        }
        if (remain_packet_len_ == 0 || // no more content
            rbuf_pos_ == kHttpMaxMessage) { // buffer full
          AppendRequestBody();
          if (remain_packet_len_ == 0) {
            conn_status_ = kComplete;
          } else {
            rbuf_pos_ = header_len_ = 0; // read more packet content from begin
          }
        }
        break;
      }
      case kComplete: {
        HandleMessage();
        conn_status_ = kHeader;
        rbuf_pos_ = 0;
        return kReadAll;
      }
      default: {
        return kReadError;
      }
    }
    // else continue
  }
}

bool HttpConn::FillResponseBuf() {
  if (response_pos_ < 0) {
    // Not ever serialize response header
    int actual = response_->SerializeHeaderToArray(wbuf_ + wbuf_len_,
        kHttpMaxMessage - wbuf_len_);
    if (actual < 0) {
      return false;
    }
    wbuf_len_ += actual;
    response_pos_ = 0; // Serialize body next time
  }
  while (response_->HasMoreBody(response_pos_)
      && wbuf_len_ < kHttpMaxMessage) {
    // Has more body and more space in wbuf_
    wbuf_len_ += response_->SerializeBodyToArray(wbuf_ + wbuf_len_,
        kHttpMaxMessage - wbuf_len_, &response_pos_);
  }
  return true;
}

WriteStatus HttpConn::SendReply() {
  // Fill as more as content into the buf
  if (!FillResponseBuf()) {
    return kWriteError;
  }

  ssize_t nwritten = 0;
  while (wbuf_len_ > 0) {
    nwritten = write(fd(), wbuf_ + wbuf_pos_, wbuf_len_ - wbuf_pos_);
    if (nwritten == -1 && errno == EAGAIN) {
      return kWriteHalf;
    } else if (nwritten <= 0) {
      return kWriteError;
    }
    wbuf_pos_ += nwritten;
    if (wbuf_pos_ == wbuf_len_) {
      // Send all in wbuf_ and Try to fill more
      wbuf_len_ = 0;
      wbuf_pos_ = 0;
      if (!FillResponseBuf()) {
        return kWriteError;
      }
    }
  }
  response_pos_ = -1; // fill header first next time

  return kWriteAll;
}

}  // namespace pink
<|endoftext|>