<commit_before>/*************************************************************************
 *
 *  $RCSfile: objectcontact.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2004-02-26 17:46:32 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SDR_CONTACT_OBJECTCONTACT_HXX
#include <svx/sdr/contact/objectcontact.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _SDR_CONTACT_VIEWOBJECTCONTACT_HXX
#include <svx/sdr/contact/viewobjectcontact.hxx>
#endif

#ifndef _SVDPAGE_HXX
#include <svdpage.hxx>
#endif

#ifndef _SDR_CONTACT_VIEWCONTACT_HXX
#include <svx/sdr/contact/viewcontact.hxx>
#endif

#ifndef _SDR_ANIMATION_OBJECTANIMATOR_HXX
#include <svx/sdr/animation/objectanimator.hxx>
#endif

#ifndef _SDR_EVENT_EVENTHANDLER_HXX
#include <svx/sdr/event/eventhandler.hxx>
#endif

//////////////////////////////////////////////////////////////////////////////

namespace sdr
{
    namespace contact
    {
        ObjectContact::ObjectContact()
        :   mpObjectAnimator(0L),
            mpEventHandler(0L),
            mbDrawHierarchyValid(sal_False)
        {
        }

        // The destructor. When PrepareDelete() was not called before (see there)
        // warnings will be generated in debug version if there are still contacts
        // existing.
        ObjectContact::~ObjectContact()
        {
#ifdef DBG_UTIL
            DBG_ASSERT(0L == maVOCList.Count(),
                "ObjectContact destructor: ViewObjectContactList is not empty, call PrepareDelete() before deleting (!)");
            DBG_ASSERT(0L == mpObjectAnimator,
                "ObjectContact destructor: still an ObjectAnimator existing, call PrepareDelete() before deleting (!)");
            DBG_ASSERT(0L == mpEventHandler,
                "ObjectContact destructor: still an EventHandler existing, call PrepareDelete() before deleting (!)");
            DBG_ASSERT(0L == maDrawHierarchy.Count(),
                "ObjectContact destructor: DrawHierarchyList is not empty, call PrepareDelete() before deleting (!)");
#endif
        }

        // Prepare deletion of this object. Tghis needs to be called always
        // before really deleting this objects. This is necessary since in a c++
        // destructor no virtual function calls are allowed. To avoid this problem,
        // it is required to first call PrepareDelete().
        void ObjectContact::PrepareDelete()
        {
            // #114735# clear DrawHierarchy, empty maDrawHierarchy
            ClearDrawHierarchy();

            // get rid of all registered contacts
            while(maVOCList.Count())
            {
                ViewObjectContact* pCandidate = maVOCList.GetLastObjectAndRemove();
                DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");

                // ViewObjectContacts only make sense with View and Object contacts.
                // When the contact to the SdrObject is deleted like in this case,
                // all ViewObjectContacts can be deleted, too.
                pCandidate->PrepareDelete();
                delete pCandidate;
            }

            // delete the ObjectAnimator. Do that after the members are deleted, since the
            // members will try to deconnect from the local ObjectAnimator.
            DeleteObjectAnimator();

            // delete the EventHandler. This will destroy all still contained events.
            DeleteEventHandler();
        }

        // A new ViewObjectContact was created and shall be remembered.
        void ObjectContact::AddViewObjectContact(ViewObjectContact& rVOContact)
        {
            maVOCList.Append(&rVOContact);
        }

        // A ViewObjectContact was deleted and shall be forgotten.
        void ObjectContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
        {
            if(maVOCList.Count())
            {
                maVOCList.Remove(&rVOContact);
            }

            // #114735# also remove from base level DrawHierarchy
            if(maDrawHierarchy.Count())
            {
                if(maDrawHierarchy.Remove(&rVOContact))
                {
                    MarkDrawHierarchyInvalid();
                }
            }
        }

        // Test if ViewObjectContact is registered here
        sal_Bool ObjectContact::ContainsViewObjectContact(ViewObjectContact& rVOContact)
        {
            return maVOCList.Contains(&rVOContact);
        }

        // Clear Draw Hierarchy data.
        void ObjectContact::ClearDrawHierarchy()
        {
            // throw away old hierarchy info
            while(maDrawHierarchy.Count())
            {
                ViewObjectContact* pCandidate = maDrawHierarchy.GetLastObjectAndRemove();
                DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");

                pCandidate->ClearDrawHierarchy();
                pCandidate->SetParent(0L);
            }
        }

        // Pre-Process the whole displaying.
        void ObjectContact::PreProcessDisplay(DisplayInfo& rDisplayInfo)
        {
            // The default implementation ensures a valid draw hierarchy.
            EnsureValidDrawHierarchy(rDisplayInfo);
        }

        // test if visualizing of entered groups is switched on at all
        sal_Bool ObjectContact::DoVisualizeEnteredGroup() const
        {
            // Don not do that as default
            return sal_False;
        }

        // Get the active group (the entered group). To get independent
        // from the old object/view classes return values use the new
        // classes.
        ViewContact* ObjectContact::GetActiveGroupContact() const
        {
            // Default has no active group
            return 0L;
        }

        // Get info about validity state of DrawHierarchy
        sal_Bool ObjectContact::IsDrawHierarchyValid() const
        {
            return mbDrawHierarchyValid;
        }

        // Take notice of invalidation of DrawHierarchy from this level. This may
        // be the removal/deletion or insertion of an object. Take preparations for reacting on that.
        void ObjectContact::MarkDrawHierarchyInvalid()
        {
            if(IsDrawHierarchyValid())
            {
                // change flag
                mbDrawHierarchyValid = sal_False;
            }
        }

        // Invalidate given rectangle at the window/output which is represented by
        // this ObjectContact.
        void ObjectContact::InvalidatePartOfView(const Rectangle& rRectangle) const
        {
            // nothing to do here in the default version
        }

        // Non-painted object was changed. Test for potentially
        // getting visible
        void ObjectContact::ObjectGettingPotentiallyVisible(const ViewObjectContact& rVOC) const
        {
            // nothing to do here in the default version
        }

        // Take some action when new objects are inserted. This is triggered from
        // the VOCs, originating from VCs.
        void ObjectContact::ActionChildInserted(const Rectangle& rInitialRectangle)
        {
            // invalidate initial object proportions to get the Paint started
            InvalidatePartOfView(rInitialRectangle);

            // Mark DrawHierarchy invalid
            MarkDrawHierarchyInvalid();
        }

        // Get info about the need to visualize GluePoints
        sal_Bool ObjectContact::AreGluePointsVisible() const
        {
            return sal_False;
        }

        // method to create a ObjectAnimator. Needs to give a result.
        sdr::animation::ObjectAnimator* ObjectContact::CreateObjectAnimator()
        {
            // Create and return a new ObjectAnimator
            return new sdr::animation::ObjectAnimator();
        }

        // method to create a EventHandler. Needs to give a result.
        sdr::event::TimerEventHandler* ObjectContact::CreateEventHandler()
        {
            // Create and return a new EventHandler
            return new sdr::event::TimerEventHandler();
        }

        // method to get the ObjectAnimator. It will
        // return a existing one or create a new one using CreateObjectAnimator().
        sdr::animation::ObjectAnimator& ObjectContact::GetObjectAnimator() const
        {
            if(!HasObjectAnimator())
            {
                ((ObjectContact*)this)->mpObjectAnimator = ((ObjectContact*)this)->CreateObjectAnimator();
                DBG_ASSERT(mpObjectAnimator,
                    "ObjectContact::GetObjectAnimator(): Got no ObjectAnimator (!)");
            }

            return *mpObjectAnimator;
        }

        // method to get the EventHandler. It will
        // return a existing one or create a new one using CreateEventHandler().
        sdr::event::TimerEventHandler& ObjectContact::GetEventHandler() const
        {
            if(!HasEventHandler())
            {
                ((ObjectContact*)this)->mpEventHandler = ((ObjectContact*)this)->CreateEventHandler();
                DBG_ASSERT(mpEventHandler,
                    "ObjectContact::GetEventHandler(): Got no EventHandler (!)");
            }

            return *mpEventHandler;
        }

        // delete the ObjectAnimator
        void ObjectContact::DeleteObjectAnimator()
        {
            if(mpObjectAnimator)
            {
                // If there are still AnimationStates registered, something has went wrong
                DBG_ASSERT(mpObjectAnimator->Count() == 0,
                    "ObjectContact::DeleteObjectAnimator: Still AnimationStates registered (!)");
                delete mpObjectAnimator;
                mpObjectAnimator = 0L;
            }
        }

        // delete the EventHandler
        void ObjectContact::DeleteEventHandler()
        {
            if(mpEventHandler)
            {
                // If there are still Events registered, something has went wrong
                delete mpEventHandler;
                mpEventHandler = 0L;
            }
        }

        // test if there is an ObjectAnimator without creating one on demand
        sal_Bool ObjectContact::HasObjectAnimator() const
        {
            return (0L != mpObjectAnimator);
        }

        // test if there is an EventHandler without creating one on demand
        sal_Bool ObjectContact::HasEventHandler() const
        {
            return (0L != mpEventHandler);
        }

        // check if text animation is allowed. Default is sal_true.
        sal_Bool ObjectContact::IsTextAnimationAllowed() const
        {
            return sal_True;
        }

        // check if graphic animation is allowed. Default is sal_true.
        sal_Bool ObjectContact::IsGraphicAnimationAllowed() const
        {
            return sal_True;
        }

        // check if asynchronious graphis loading is allowed. Default is sal_False.
        sal_Bool ObjectContact::IsAsynchronGraphicsLoadingAllowed() const
        {
            return sal_False;
        }
    } // end of namespace contact
} // end of namespace sdr

//////////////////////////////////////////////////////////////////////////////
// eof
<commit_msg>INTEGRATION: CWS aw013 (1.3.194); FILE MERGED 2004/06/11 16:10:23 aw 1.3.194.1: #114389#, #114394#<commit_after>/*************************************************************************
 *
 *  $RCSfile: objectcontact.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-12 14:39:43 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SDR_CONTACT_OBJECTCONTACT_HXX
#include <svx/sdr/contact/objectcontact.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _SDR_CONTACT_VIEWOBJECTCONTACT_HXX
#include <svx/sdr/contact/viewobjectcontact.hxx>
#endif

#ifndef _SVDPAGE_HXX
#include <svdpage.hxx>
#endif

#ifndef _SDR_CONTACT_VIEWCONTACT_HXX
#include <svx/sdr/contact/viewcontact.hxx>
#endif

#ifndef _SDR_ANIMATION_OBJECTANIMATOR_HXX
#include <svx/sdr/animation/objectanimator.hxx>
#endif

#ifndef _SDR_EVENT_EVENTHANDLER_HXX
#include <svx/sdr/event/eventhandler.hxx>
#endif

//////////////////////////////////////////////////////////////////////////////

namespace sdr
{
    namespace contact
    {
        ObjectContact::ObjectContact()
        :   mpObjectAnimator(0L),
            mpEventHandler(0L),
            mpViewObjectContactRedirector(0L),
            mbDrawHierarchyValid(sal_False)
        {
        }

        // The destructor. When PrepareDelete() was not called before (see there)
        // warnings will be generated in debug version if there are still contacts
        // existing.
        ObjectContact::~ObjectContact()
        {
#ifdef DBG_UTIL
            DBG_ASSERT(0L == maVOCList.Count(),
                "ObjectContact destructor: ViewObjectContactList is not empty, call PrepareDelete() before deleting (!)");
            DBG_ASSERT(0L == mpObjectAnimator,
                "ObjectContact destructor: still an ObjectAnimator existing, call PrepareDelete() before deleting (!)");
            DBG_ASSERT(0L == mpEventHandler,
                "ObjectContact destructor: still an EventHandler existing, call PrepareDelete() before deleting (!)");
            DBG_ASSERT(0L == maDrawHierarchy.Count(),
                "ObjectContact destructor: DrawHierarchyList is not empty, call PrepareDelete() before deleting (!)");
#endif
        }

        // Prepare deletion of this object. Tghis needs to be called always
        // before really deleting this objects. This is necessary since in a c++
        // destructor no virtual function calls are allowed. To avoid this problem,
        // it is required to first call PrepareDelete().
        void ObjectContact::PrepareDelete()
        {
            // #114735# clear DrawHierarchy, empty maDrawHierarchy
            ClearDrawHierarchy();

            // get rid of all registered contacts
            while(maVOCList.Count())
            {
                ViewObjectContact* pCandidate = maVOCList.GetLastObjectAndRemove();
                DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");

                // ViewObjectContacts only make sense with View and Object contacts.
                // When the contact to the SdrObject is deleted like in this case,
                // all ViewObjectContacts can be deleted, too.
                pCandidate->PrepareDelete();
                delete pCandidate;
            }

            // delete the ObjectAnimator. Do that after the members are deleted, since the
            // members will try to deconnect from the local ObjectAnimator.
            DeleteObjectAnimator();

            // delete the EventHandler. This will destroy all still contained events.
            DeleteEventHandler();
        }

        // A new ViewObjectContact was created and shall be remembered.
        void ObjectContact::AddViewObjectContact(ViewObjectContact& rVOContact)
        {
            maVOCList.Append(&rVOContact);
        }

        // A ViewObjectContact was deleted and shall be forgotten.
        void ObjectContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
        {
            if(maVOCList.Count())
            {
                maVOCList.Remove(&rVOContact);
            }

            // #114735# also remove from base level DrawHierarchy
            if(maDrawHierarchy.Count())
            {
                if(maDrawHierarchy.Remove(&rVOContact))
                {
                    MarkDrawHierarchyInvalid();
                }
            }
        }

        // Test if ViewObjectContact is registered here
        sal_Bool ObjectContact::ContainsViewObjectContact(ViewObjectContact& rVOContact)
        {
            return maVOCList.Contains(&rVOContact);
        }

        // Clear Draw Hierarchy data.
        void ObjectContact::ClearDrawHierarchy()
        {
            // throw away old hierarchy info
            while(maDrawHierarchy.Count())
            {
                ViewObjectContact* pCandidate = maDrawHierarchy.GetLastObjectAndRemove();
                DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");

                pCandidate->ClearDrawHierarchy();
                pCandidate->SetParent(0L);
            }
        }

        // Pre-Process the whole displaying.
        void ObjectContact::PreProcessDisplay(DisplayInfo& rDisplayInfo)
        {
            // The default implementation ensures a valid draw hierarchy.
            EnsureValidDrawHierarchy(rDisplayInfo);
        }

        // test if visualizing of entered groups is switched on at all
        sal_Bool ObjectContact::DoVisualizeEnteredGroup() const
        {
            // Don not do that as default
            return sal_False;
        }

        // Get the active group (the entered group). To get independent
        // from the old object/view classes return values use the new
        // classes.
        ViewContact* ObjectContact::GetActiveGroupContact() const
        {
            // Default has no active group
            return 0L;
        }

        // Get info about validity state of DrawHierarchy
        sal_Bool ObjectContact::IsDrawHierarchyValid() const
        {
            return mbDrawHierarchyValid;
        }

        // Take notice of invalidation of DrawHierarchy from this level. This may
        // be the removal/deletion or insertion of an object. Take preparations for reacting on that.
        void ObjectContact::MarkDrawHierarchyInvalid()
        {
            if(IsDrawHierarchyValid())
            {
                // change flag
                mbDrawHierarchyValid = sal_False;
            }
        }

        // Invalidate given rectangle at the window/output which is represented by
        // this ObjectContact.
        void ObjectContact::InvalidatePartOfView(const Rectangle& rRectangle) const
        {
            // nothing to do here in the default version
        }

        // Non-painted object was changed. Test for potentially
        // getting visible
        void ObjectContact::ObjectGettingPotentiallyVisible(const ViewObjectContact& rVOC) const
        {
            // nothing to do here in the default version
        }

        // Take some action when new objects are inserted. This is triggered from
        // the VOCs, originating from VCs.
        void ObjectContact::ActionChildInserted(const Rectangle& rInitialRectangle)
        {
            // invalidate initial object proportions to get the Paint started
            InvalidatePartOfView(rInitialRectangle);

            // Mark DrawHierarchy invalid
            MarkDrawHierarchyInvalid();
        }

        // Get info about the need to visualize GluePoints
        sal_Bool ObjectContact::AreGluePointsVisible() const
        {
            return sal_False;
        }

        // method to create a ObjectAnimator. Needs to give a result.
        sdr::animation::ObjectAnimator* ObjectContact::CreateObjectAnimator()
        {
            // Create and return a new ObjectAnimator
            return new sdr::animation::ObjectAnimator();
        }

        // method to create a EventHandler. Needs to give a result.
        sdr::event::TimerEventHandler* ObjectContact::CreateEventHandler()
        {
            // Create and return a new EventHandler
            return new sdr::event::TimerEventHandler();
        }

        // method to get the ObjectAnimator. It will
        // return a existing one or create a new one using CreateObjectAnimator().
        sdr::animation::ObjectAnimator& ObjectContact::GetObjectAnimator() const
        {
            if(!HasObjectAnimator())
            {
                ((ObjectContact*)this)->mpObjectAnimator = ((ObjectContact*)this)->CreateObjectAnimator();
                DBG_ASSERT(mpObjectAnimator,
                    "ObjectContact::GetObjectAnimator(): Got no ObjectAnimator (!)");
            }

            return *mpObjectAnimator;
        }

        // method to get the EventHandler. It will
        // return a existing one or create a new one using CreateEventHandler().
        sdr::event::TimerEventHandler& ObjectContact::GetEventHandler() const
        {
            if(!HasEventHandler())
            {
                ((ObjectContact*)this)->mpEventHandler = ((ObjectContact*)this)->CreateEventHandler();
                DBG_ASSERT(mpEventHandler,
                    "ObjectContact::GetEventHandler(): Got no EventHandler (!)");
            }

            return *mpEventHandler;
        }

        // delete the ObjectAnimator
        void ObjectContact::DeleteObjectAnimator()
        {
            if(mpObjectAnimator)
            {
                // If there are still AnimationStates registered, something has went wrong
                DBG_ASSERT(mpObjectAnimator->Count() == 0,
                    "ObjectContact::DeleteObjectAnimator: Still AnimationStates registered (!)");
                delete mpObjectAnimator;
                mpObjectAnimator = 0L;
            }
        }

        // delete the EventHandler
        void ObjectContact::DeleteEventHandler()
        {
            if(mpEventHandler)
            {
                // If there are still Events registered, something has went wrong
                delete mpEventHandler;
                mpEventHandler = 0L;
            }
        }

        // test if there is an ObjectAnimator without creating one on demand
        sal_Bool ObjectContact::HasObjectAnimator() const
        {
            return (0L != mpObjectAnimator);
        }

        // test if there is an EventHandler without creating one on demand
        sal_Bool ObjectContact::HasEventHandler() const
        {
            return (0L != mpEventHandler);
        }

        // check if text animation is allowed. Default is sal_true.
        sal_Bool ObjectContact::IsTextAnimationAllowed() const
        {
            return sal_True;
        }

        // check if graphic animation is allowed. Default is sal_true.
        sal_Bool ObjectContact::IsGraphicAnimationAllowed() const
        {
            return sal_True;
        }

        // check if asynchronious graphis loading is allowed. Default is sal_False.
        sal_Bool ObjectContact::IsAsynchronGraphicsLoadingAllowed() const
        {
            return sal_False;
        }

        // access to ViewObjectContactRedirector
        ViewObjectContactRedirector* ObjectContact::GetViewObjectContactRedirector() const
        {
            return mpViewObjectContactRedirector;
        }

        void ObjectContact::SetViewObjectContactRedirector(ViewObjectContactRedirector* pNew)
        {
            if(mpViewObjectContactRedirector != pNew)
            {
                mpViewObjectContactRedirector = pNew;
            }
        }
    } // end of namespace contact
} // end of namespace sdr

//////////////////////////////////////////////////////////////////////////////
// eof
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include <stdexcept>

#include "Token.hpp"
#include "Instruction.hpp"

class SemanticAnalyser
{
public:
  class InvalidSemantic : public std::runtime_error
  {
  public:
    InvalidSemantic(const std::string& msg) : std::runtime_error{msg}
    {
    }
  };

  Instructions analyse(const Tokens& tokens)
  {
    if (tokens.empty())
    {
      return {};
    }
    if (tokens.size() == 3)
    {
      if (areTokensValidLdInstruction(tokens.cbegin()))
      {
        return {{InstructionType::LdA, 0}};
      }
      else if (areTokensValidOutInstruction(tokens.cbegin()))
      {
        return {{InstructionType::OutA, 0}};
      }
    }
    throw InvalidSemantic{"Invalid instruction"};
  }

private:
  bool areTokensValidOutInstruction(Tokens::const_iterator begin)
  {
    return (begin++)->type == TokenType::Out
        && (begin++)->type == TokenType::ZeroWithBrackets
        && (begin++)->type == TokenType::A;
  }

  bool areTokensValidLdInstruction(Tokens::const_iterator begin)
  {
    return (begin++)->type == TokenType::Ld
        && (begin++)->type == TokenType::A
        && (begin++)->type == TokenType::Number8Bit;
  }
};

using namespace ::testing;

struct SemanticAnalyserTest : public Test
{
  SemanticAnalyser analyser;

  static constexpr Token createTokenWithZeroValue(TokenType type)
  {
    return{type, 0};
  }

  static constexpr Instruction createInstructionWithZeroValue(InstructionType type)
  {
    return{type, 0};
  }
};

TEST_F(SemanticAnalyserTest, ShouldAcceptEmptyTokens)
{
  Tokens tokens{};
  Instructions instructions;
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstructionSet)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptLdInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Number8Bit)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::LdA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                createTokenWithZeroValue(TokenType::ZeroWithBrackets),
                createTokenWithZeroValue(TokenType::A)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::OutA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                createTokenWithZeroValue(TokenType::Number8Bit),
                createTokenWithZeroValue(TokenType::A)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldRejectInvalidLdInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Out)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}<commit_msg>SemanticAnalyser Rejects invalid Ld instruction<commit_after>#include "gtest/gtest.h"

#include <stdexcept>

#include "Token.hpp"
#include "Instruction.hpp"

class SemanticAnalyser
{
public:
  class InvalidSemantic : public std::runtime_error
  {
  public:
    InvalidSemantic(const std::string& msg) : std::runtime_error{msg}
    {
    }
  };

  Instructions analyse(const Tokens& tokens)
  {
    if (tokens.empty())
    {
      return {};
    }
    if (tokens.size() == 3)
    {
      if (areTokensValidLdInstruction(tokens.cbegin()))
      {
        return {{InstructionType::LdA, 0}};
      }
      else if (areTokensValidOutInstruction(tokens.cbegin()))
      {
        return {{InstructionType::OutA, 0}};
      }
    }
    throw InvalidSemantic{"Invalid instruction"};
  }

private:
  bool areTokensValidOutInstruction(Tokens::const_iterator begin)
  {
    return (begin++)->type == TokenType::Out
        && (begin++)->type == TokenType::ZeroWithBrackets
        && (begin++)->type == TokenType::A;
  }

  bool areTokensValidLdInstruction(Tokens::const_iterator begin)
  {
    return (begin++)->type == TokenType::Ld
        && (begin++)->type == TokenType::A
        && (begin++)->type == TokenType::Number8Bit;
  }
};

using namespace ::testing;

struct SemanticAnalyserTest : public Test
{
  SemanticAnalyser analyser;

  static constexpr Token createTokenWithZeroValue(TokenType type)
  {
    return{type, 0};
  }

  static constexpr Instruction createInstructionWithZeroValue(InstructionType type)
  {
    return{type, 0};
  }
};

TEST_F(SemanticAnalyserTest, ShouldAcceptEmptyTokens)
{
  Tokens tokens{};
  Instructions instructions;
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstructionSet)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptLdInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Number8Bit)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::LdA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                createTokenWithZeroValue(TokenType::ZeroWithBrackets),
                createTokenWithZeroValue(TokenType::A)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::OutA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}

TEST_F(SemanticAnalyserTest, ShouldNotAcceptInvalidInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                createTokenWithZeroValue(TokenType::Number8Bit),
                createTokenWithZeroValue(TokenType::A)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldRejectInvalidLdInstruction)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Ld),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Out)};
  ASSERT_THROW(analyser.analyse(tokens), SemanticAnalyser::InvalidSemantic);
}

TEST_F(SemanticAnalyserTest, ShouldAcceptOutInstructionFollowedByLd)
{
  Tokens tokens{createTokenWithZeroValue(TokenType::Out),
                createTokenWithZeroValue(TokenType::ZeroWithBrackets),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Ld),
                createTokenWithZeroValue(TokenType::A),
                createTokenWithZeroValue(TokenType::Out)};
  Instructions instructions{createInstructionWithZeroValue(InstructionType::OutA), createInstructionWithZeroValue(InstructionType::LdA)};
  ASSERT_EQ(instructions, analyser.analyse(tokens));
}<|endoftext|>


<commit_before>#include "sift.hpp"

#include <iostream>
#include <vector>
#include <string>
#include <tuple>
#include <cassert>

#include <vigra/convolution.hxx>
#include <vigra/resizeimage.hxx>
#include <vigra/impex.hxx>
#include <vigra/multi_math.hxx>
#include <vigra/linear_algebra.hxx>
#include <vigra/tinyvector.hxx>

#include "point.hpp"

using namespace vigra::multi_math;

void Sift::calculate(
    vigra::MultiArray<2, f32_t>& img, u16_t epochs, f32_t sigma, f32_t k, u16_t dogPerEpoch) const
{
    auto dogs = _createDOGs(img, epochs, sigma, k, dogPerEpoch);
    auto interestPoints = _findScaleSpaceExtrema(dogs);
    //Save img with found interest points for demonstration purposes
    auto img_output1 = img;
    for (auto& img : interestPoints[0]) {
        for(u16_t x = 0; x < img.width(); x++) {
            for(u16_t y = 0; y < img.height(); y++) {
                if (img[Point(x, y)] > -1) {
                    img_output1(x, y) = 255;
                }
            }
        }
    }

    exportImage(img_output1, vigra::ImageExportInfo("images/interest_points.png"));
    _keypointLocation(interestPoints, dogs);

    auto img_output2 = img;
    for (auto& img : interestPoints[0]) {
        for(u16_t x = 0; x < img.width(); x++) {
            for(u16_t y = 0; y < img.height(); y++) {
                if (img[Point(x, y)] > -1) {
                    img_output2(x, y) = 255;
                }
            }
        }
    }

    exportImage(img_output2, vigra::ImageExportInfo("images/after_keypointLocation.png"));
    }

void Sift::_keypointLocation(interest_point_epochs& interestPoints, const img_epochs& dogs) const {
    assert(dogs.size() == interestPoints.size());
    for(u16_t e = 0; e < dogs.size(); e++) {
        assert(dogs[e].size() >= 3);
        assert(interestPoints[e].size() == dogs[e].size() / 3);
        for (u16_t i = 1; i < dogs[e].size() - 1; i++) {
            assert(dogs[e][i].shape(0) == interestPoints[e][i - 1].width());
            assert(dogs[e][i].shape(1) == interestPoints[e][i - 1].height());
            for (u16_t x = 1; x < dogs[e][i].shape(0) - 1; x++) {
                for (u16_t y = 1; y < dogs[e][i].shape(1) - 1; y++) {
                    if (interestPoints[e][i - 1](x, y) > -1) {
                        auto d = dogs[e][i];
                        assert(d.shape(0) > 2);
                        assert(d.shape(1) > 2);

                        f32_t dx = (d(x - 1, y) - d(x + 1, y)) / 2;
                        f32_t dy = (d(x, y - 1) - d(x, y + 1)) / 2;
                        f32_t ds = (dogs[e][i - 1](x, y) - dogs[e][i + 1](x, y)) / 2;

                        f32_t dxx = d(x + 1, y) + d(x - 1, y) - 2 * d(x, y);
                        f32_t dyy = d(x, y + 1) + d(x, y - 1) - 2 * d(x, y);
                        f32_t dss = dogs[e][i + 1](x, y) + dogs[e][i - 1](x, y) - 2 * d(x, y);
                        f32_t dxy = d(x + 1, y + 1) - d(x - 1, y + 1) - d(x + 1, y - 1)
                            + d(x - 1, y - 1);
                        f32_t dxs = dogs[e][i + 1](x + 1, y) - dogs[e][i + 1](x - 1, y)
                            - dogs[e][i - 1](x + 1, y) + dogs[e][i - 1](x - 1, y);

                        f32_t dys = dogs[e][i + 1](x, y + 1) - dogs[e][i + 1](x, y + 1)
                            - dogs[e][i - 1](x, y + 1) + dogs[e][i - 1](x, y - 1);
                        vigra::MultiArray<2, f32_t> sec_deriv(vigra::Shape2(3, 3));
                        sec_deriv(0, 0) = dxx;
                        sec_deriv(0, 1) = dxy;
                        sec_deriv(0, 2) = dxs;
                        sec_deriv(1, 0) = dxy;
                        sec_deriv(1, 1) = dyy;
                        sec_deriv(1, 2) = dys;
                        sec_deriv(2, 0) = dxs;
                        sec_deriv(2, 1) = dys;
                        sec_deriv(2, 2) = dss;

                        vigra::TinyVector<f32_t, 3> deriv(dx, dy, ds);
                        deriv[0] = dx;
                        deriv[1] = dy;
                        deriv[2] = ds;
                        auto extremum =  vigra::linalg::operator*(vigra::linalg::inverse(sec_deriv), deriv);

                        //Calculated up 0.5 from paper to image values [0,255]
                        if (extremum[0] > 127.5 || extremum[1] > 127.5 || extremum[2] > 127.5) {
                            interestPoints[e][i - 1](x, y) = -1;
                            continue;
                        }

                        auto func_val_extremum = vigra::operator*(deriv, extremum);
                        func_val_extremum *= 0.5;
                        func_val_extremum[0] += d(x,y);
                        func_val_extremum[1] += d(x,y);
                        func_val_extremum[2] += d(x,y);
                        //Calculated up 0.03 from paper to image values[0, 255]
                        if (func_val_extremum[0] < 7.65 && func_val_extremum[1] > 7.65
                                && func_val_extremum[2] < 7.65) {
                            interestPoints[e][i - 1](x, y) = -1;
                            continue;
                        }
                    }
                }
            }
        }
    }
}

const interest_point_epochs Sift::_findScaleSpaceExtrema(const img_epochs& dogs) const {
    //a Vector with epochs containing tuples of interest points found per epoch
    interest_point_epochs interestPoints;
    for (u16_t e = 0; e < dogs.size(); e++) {
        interestPoints.emplace_back(std::vector<Matrix<f32_t>>());
        for (u16_t i = 1; i < dogs[e].size() - 1; i++) {
            interestPoints[e].emplace_back(Matrix<f32_t>(dogs[e][i].shape(0), dogs[e][i].shape(1), -1));
            for (i32_t x = 0; x < dogs[e][i].shape(0); x++) {
                for (i32_t y = 0; y < dogs[e][i].shape(1); y++) {
                    auto leftUpCorner = vigra::Shape2(x - 1, y - 1);
                    auto rightDownCorner = vigra::Shape2(x + 1, y + 1);

                    //Get the neighborhood of the current pixel
                    auto current = dogs[e][i].subarray(leftUpCorner, rightDownCorner);
                    //Get neighborhood of adjacent DOGs
                    auto under = dogs[e][i - 1].subarray(leftUpCorner, rightDownCorner);
                    auto above = dogs[e][i + 1].subarray(leftUpCorner, rightDownCorner);
                    //Check all neighborhood pixels of current and adjacent DOGs. If there isn't any
                    //pixel bigger or smaller than the current. We found an extremum.
                    if ((!any(current > dogs[e][i](x, y)) &&
                                !any(under > dogs[e][i](x, y)) &&
                                !any(above > dogs[e][i](x, y))) ||
                            (!any(current < dogs[e][i](x, y)) &&
                             !any(under < dogs[e][i](x, y)) &&
                             !any(above < dogs[e][i](x, y))))
                    {
                        interestPoints[e].back()[Point(x, y)] = dogs[e][i](x, y);
                    }
                    else
                        interestPoints[e].back()[Point(x, y)] = -1;
                }
            }
        }
    }
    return interestPoints; // TODO: by ref entgegen nehmen, um copy zu vermeiden?
}

const img_epochs Sift::_createDOGs(vigra::MultiArray<2, f32_t>& img, u16_t epochs, f32_t sigma,
        f32_t k, u16_t dogPerEpoch) const {

    assert(epochs > 0); // pre condition
    assert(dogPerEpoch >= 3); // pre condition

    /*
     * A vector which contains a vector for each epoch. Those are filled with the
     * Images which were created from the laplacianOfGaussians.
     */
    img_epochs laplacians;
    /*
     * a vector which contains a vector for each epoch. Those are filled with the
     * images which were created from gaussians
     */
    img_epochs gaussians;

    //add inital image
    gaussians.emplace_back(std::vector<vigra::MultiArray<2, f32_t>>());
    gaussians[0].emplace_back(_convolveWithGauss(img, sigma));

    //TODO: More elegant way?
    u16_t exp = 0;
    for (i32_t i = 0; i < epochs; i++) {
        laplacians.emplace_back(std::vector<vigra::MultiArray<2, f32_t>>());
        for (i32_t j = 1; j < dogPerEpoch + 1; j++) {
            gaussians[i].emplace_back(_convolveWithGauss(gaussians[i][j - 1], std::pow(k, exp) * sigma));
            laplacians[i].emplace_back(_DOG(gaussians[i][j - 1], gaussians[i][j]));
            exp++;
        }
        /*
         * If we aren't in the last epoch populate the next level with the second
         * last element, scaled won by a half, of the gaussians.
         */
        if (i < (epochs - 1)) {
            gaussians.emplace_back(std::vector<vigra::MultiArray<2, f32_t>>());
            auto scaledElem = _reduceToNextLevel(gaussians[i][dogPerEpoch - 1], sigma);
            gaussians[i + 1].emplace_back(scaledElem);

            exp -= 2;
        }
    }

    //Save laplacianOfGaussian for Demonstration purposes
    for (u16_t i = 0; i < laplacians.size(); i++) {
        for (u16_t j = 0; j < laplacians[i].size(); j++) {
            const std::string fnStr = "images/laplacian" + std::to_string(i) + std::to_string(j) + ".png";
            exportImage(laplacians[i][j], vigra::ImageExportInfo(fnStr.c_str()));
        }
    }

    return laplacians; // TODO: by ref entgegen nehmen um copy zu vermeiden?
}

const vigra::MultiArray<2, f32_t> Sift::_reduceToNextLevel(const vigra::MultiArray<2, f32_t>& in,
        f32_t sigma) const {
    // image size at current level
    const u16_t height = in.height();
    const u16_t width = in.width();

    // image size at next smaller level
    const u16_t newheight = (height + 1) / 2;
    const u16_t newwidth = (width + 1) / 2;

    // resize result image to appropriate size
    vigra::MultiArray<2, f32_t> out(vigra::Shape2(newwidth, newheight));
    // downsample smoothed image
    resizeImageNoInterpolation(_convolveWithGauss(in, sigma), out);

    return out; // TODO by ref entgegen nehmen um copy zu vermeiden?
}

const vigra::MultiArray<2, f32_t> Sift::_convolveWithGauss(const vigra::MultiArray<2, f32_t>& input,
        f32_t sigma) const {

    vigra::Kernel1D<f32_t> filter;
    filter.initGaussian(sigma);
    vigra::MultiArray<2, f32_t> tmp(input.shape());
    vigra::MultiArray<2, f32_t> result(input.shape());

    separableConvolveX(input, tmp, filter);
    separableConvolveY(tmp, result, filter);

    return result;
}

const vigra::MultiArray<2, f32_t> Sift::_DOG(const vigra::MultiArray<2, f32_t>& lower,
        const vigra::MultiArray<2, f32_t>& higher) const {

    vigra::MultiArray<2, f32_t> result(vigra::Shape2(lower.shape()));
    for(u16_t x = 0; x < lower.shape(0); x++) {
        for(u16_t y = 0; y < lower.shape(1); y++) {
            f32_t dif = higher(x, y) - lower(x, y);
            result(x, y) = 128 + dif;
        }
    }
    return result;
}
<commit_msg>some cleanup<commit_after>#include "sift.hpp"

#include <iostream>
#include <vector>
#include <string>
#include <tuple>
#include <cassert>

#include <vigra/convolution.hxx>
#include <vigra/resizeimage.hxx>
#include <vigra/impex.hxx>
#include <vigra/multi_math.hxx>
#include <vigra/linear_algebra.hxx>
#include <vigra/tinyvector.hxx>

#include "point.hpp"

using namespace vigra::multi_math;

void Sift::calculate(
    vigra::MultiArray<2, f32_t>& img, u16_t epochs, f32_t sigma, f32_t k, u16_t dogPerEpoch) const
{
    auto dogs = _createDOGs(img, epochs, sigma, k, dogPerEpoch);
    auto interestPoints = _findScaleSpaceExtrema(dogs);
    //Save img with found interest points for demonstration purposes
    auto img_output1 = img;
    for (auto& img : interestPoints[0]) {
        for(u16_t x = 0; x < img.width(); x++) {
            for(u16_t y = 0; y < img.height(); y++) {
                if (img[Point(x, y)] > -1) {
                    img_output1(x, y) = 255;
                }
            }
        }
    }

    exportImage(img_output1, vigra::ImageExportInfo("images/interest_points.png"));
    _keypointLocation(interestPoints, dogs);

    auto img_output2 = img;
    for (auto& img : interestPoints[0]) {
        for(u16_t x = 0; x < img.width(); x++) {
            for(u16_t y = 0; y < img.height(); y++) {
                if (img[Point(x, y)] > -1) {
                    img_output2(x, y) = 255;
                }
            }
        }
    }

    exportImage(img_output2, vigra::ImageExportInfo("images/after_keypointLocation.png"));
    }

void Sift::_keypointLocation(interest_point_epochs& interestPoints, const img_epochs& dogs) const {
    assert(dogs.size() == interestPoints.size());
    for(u16_t e = 0; e < dogs.size(); e++) {
        assert(dogs[e].size() >= 3);
        assert(interestPoints[e].size() == dogs[e].size() / 3);
        for (u16_t i = 1; i < dogs[e].size() - 1; i++) {
            assert(dogs[e][i].shape(0) == interestPoints[e][i - 1].width());
            assert(dogs[e][i].shape(1) == interestPoints[e][i - 1].height());
            for (u16_t x = 1; x < dogs[e][i].shape(0) - 1; x++) {
                for (u16_t y = 1; y < dogs[e][i].shape(1) - 1; y++) {
                    if (interestPoints[e][i - 1](x, y) > -1) {
                        auto d = dogs[e][i];
                        assert(d.shape(0) > 2);
                        assert(d.shape(1) > 2);

                        f32_t dx = (d(x - 1, y) - d(x + 1, y)) / 2;
                        f32_t dy = (d(x, y - 1) - d(x, y + 1)) / 2;
                        f32_t ds = (dogs[e][i - 1](x, y) - dogs[e][i + 1](x, y)) / 2;

                        f32_t dxx = d(x + 1, y) + d(x - 1, y) - 2 * d(x, y);
                        f32_t dyy = d(x, y + 1) + d(x, y - 1) - 2 * d(x, y);
                        f32_t dss = dogs[e][i + 1](x, y) + dogs[e][i - 1](x, y) - 2 * d(x, y);
                        f32_t dxy = d(x + 1, y + 1) - d(x - 1, y + 1) - d(x + 1, y - 1)
                            + d(x - 1, y - 1);
                        f32_t dxs = dogs[e][i + 1](x + 1, y) - dogs[e][i + 1](x - 1, y)
                            - dogs[e][i - 1](x + 1, y) + dogs[e][i - 1](x - 1, y);

                        f32_t dys = dogs[e][i + 1](x, y + 1) - dogs[e][i + 1](x, y + 1)
                            - dogs[e][i - 1](x, y + 1) + dogs[e][i - 1](x, y - 1);
                        vigra::MultiArray<2, f32_t> sec_deriv(vigra::Shape2(3, 3));
                        sec_deriv(0, 0) = dxx;
                        sec_deriv(0, 1) = dxy;
                        sec_deriv(0, 2) = dxs;
                        sec_deriv(1, 0) = dxy;
                        sec_deriv(1, 1) = dyy;
                        sec_deriv(1, 2) = dys;
                        sec_deriv(2, 0) = dxs;
                        sec_deriv(2, 1) = dys;
                        sec_deriv(2, 2) = dss;

                        vigra::TinyVector<f32_t, 3> deriv(dx, dy, ds);
                        auto extremum =  vigra::linalg::operator*(vigra::linalg::inverse(sec_deriv), deriv);

                        //Calculated up 0.5 from paper to image values [0,255]
                        if (extremum[0] > 127.5 || extremum[1] > 127.5 || extremum[2] > 127.5) {
                            interestPoints[e][i - 1](x, y) = -1;
                            continue;
                        }

                        auto func_val_extremum = vigra::operator*(deriv, extremum);
                        func_val_extremum *= 0.5;
                        func_val_extremum[0] += d(x,y);
                        func_val_extremum[1] += d(x,y);
                        func_val_extremum[2] += d(x,y);
                        //Calculated up 0.03 from paper to image values[0, 255]
                        if (func_val_extremum[0] + func_val_extremum[1] + func_val_extremum[2] < 7.65) {
                            interestPoints[e][i - 1](x, y) = -1;
                            continue;
                        }
                    }
                }
            }
        }
    }
}

const interest_point_epochs Sift::_findScaleSpaceExtrema(const img_epochs& dogs) const {
    //a Vector with epochs containing tuples of interest points found per epoch
    interest_point_epochs interestPoints;
    for (u16_t e = 0; e < dogs.size(); e++) {
        interestPoints.emplace_back(std::vector<Matrix<f32_t>>());
        for (u16_t i = 1; i < dogs[e].size() - 1; i++) {
            interestPoints[e].emplace_back(Matrix<f32_t>(dogs[e][i].shape(0), dogs[e][i].shape(1), -1));
            for (i32_t x = 0; x < dogs[e][i].shape(0); x++) {
                for (i32_t y = 0; y < dogs[e][i].shape(1); y++) {
                    auto leftUpCorner = vigra::Shape2(x - 1, y - 1);
                    auto rightDownCorner = vigra::Shape2(x + 1, y + 1);

                    //Get the neighborhood of the current pixel
                    auto current = dogs[e][i].subarray(leftUpCorner, rightDownCorner);
                    //Get neighborhood of adjacent DOGs
                    auto under = dogs[e][i - 1].subarray(leftUpCorner, rightDownCorner);
                    auto above = dogs[e][i + 1].subarray(leftUpCorner, rightDownCorner);
                    //Check all neighborhood pixels of current and adjacent DOGs. If there isn't any
                    //pixel bigger or smaller than the current. We found an extremum.
                    if ((!any(current > dogs[e][i](x, y)) &&
                                !any(under > dogs[e][i](x, y)) &&
                                !any(above > dogs[e][i](x, y))) ||
                            (!any(current < dogs[e][i](x, y)) &&
                             !any(under < dogs[e][i](x, y)) &&
                             !any(above < dogs[e][i](x, y))))
                    {
                        interestPoints[e].back()[Point(x, y)] = dogs[e][i](x, y);
                    }
                    else
                        interestPoints[e].back()[Point(x, y)] = -1;
                }
            }
        }
    }
    return interestPoints; // TODO: by ref entgegen nehmen, um copy zu vermeiden?
}

const img_epochs Sift::_createDOGs(vigra::MultiArray<2, f32_t>& img, u16_t epochs, f32_t sigma,
        f32_t k, u16_t dogPerEpoch) const {

    assert(epochs > 0); // pre condition
    assert(dogPerEpoch >= 3); // pre condition

    /*
     * A vector which contains a vector for each epoch. Those are filled with the
     * Images which were created from the laplacianOfGaussians.
     */
    img_epochs laplacians;
    /*
     * a vector which contains a vector for each epoch. Those are filled with the
     * images which were created from gaussians
     */
    img_epochs gaussians;

    //add inital image
    gaussians.emplace_back(std::vector<vigra::MultiArray<2, f32_t>>());
    gaussians[0].emplace_back(_convolveWithGauss(img, sigma));

    //TODO: More elegant way?
    u16_t exp = 0;
    for (i32_t i = 0; i < epochs; i++) {
        laplacians.emplace_back(std::vector<vigra::MultiArray<2, f32_t>>());
        for (i32_t j = 1; j < dogPerEpoch + 1; j++) {
            gaussians[i].emplace_back(_convolveWithGauss(gaussians[i][j - 1], std::pow(k, exp) * sigma));
            laplacians[i].emplace_back(_DOG(gaussians[i][j - 1], gaussians[i][j]));
            exp++;
        }
        /*
         * If we aren't in the last epoch populate the next level with the second
         * last element, scaled won by a half, of the gaussians.
         */
        if (i < (epochs - 1)) {
            gaussians.emplace_back(std::vector<vigra::MultiArray<2, f32_t>>());
            auto scaledElem = _reduceToNextLevel(gaussians[i][dogPerEpoch - 1], sigma);
            gaussians[i + 1].emplace_back(scaledElem);

            exp -= 2;
        }
    }

    //Save laplacianOfGaussian for Demonstration purposes
    for (u16_t i = 0; i < laplacians.size(); i++) {
        for (u16_t j = 0; j < laplacians[i].size(); j++) {
            const std::string fnStr = "images/laplacian" + std::to_string(i) + std::to_string(j) + ".png";
            exportImage(laplacians[i][j], vigra::ImageExportInfo(fnStr.c_str()));
        }
    }

    return laplacians; // TODO: by ref entgegen nehmen um copy zu vermeiden?
}

const vigra::MultiArray<2, f32_t> Sift::_reduceToNextLevel(const vigra::MultiArray<2, f32_t>& in,
        f32_t sigma) const {
    // image size at current level
    const u16_t height = in.height();
    const u16_t width = in.width();

    // image size at next smaller level
    const u16_t newheight = (height + 1) / 2;
    const u16_t newwidth = (width + 1) / 2;

    // resize result image to appropriate size
    vigra::MultiArray<2, f32_t> out(vigra::Shape2(newwidth, newheight));
    // downsample smoothed image
    resizeImageNoInterpolation(_convolveWithGauss(in, sigma), out);

    return out; // TODO by ref entgegen nehmen um copy zu vermeiden?
}

const vigra::MultiArray<2, f32_t> Sift::_convolveWithGauss(const vigra::MultiArray<2, f32_t>& input,
        f32_t sigma) const {

    vigra::Kernel1D<f32_t> filter;
    filter.initGaussian(sigma);
    vigra::MultiArray<2, f32_t> tmp(input.shape());
    vigra::MultiArray<2, f32_t> result(input.shape());

    separableConvolveX(input, tmp, filter);
    separableConvolveY(tmp, result, filter);

    return result;
}

const vigra::MultiArray<2, f32_t> Sift::_DOG(const vigra::MultiArray<2, f32_t>& lower,
        const vigra::MultiArray<2, f32_t>& higher) const {

    vigra::MultiArray<2, f32_t> result(vigra::Shape2(lower.shape()));
    for(u16_t x = 0; x < lower.shape(0); x++) {
        for(u16_t y = 0; y < lower.shape(1); y++) {
            f32_t dif = higher(x, y) - lower(x, y);
            result(x, y) = 128 + dif;
        }
    }
    return result;
}
<|endoftext|>


<commit_before>#include <cmux/c_api.h>
#include <stdexcept>

#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include "CMUXInstance.h"
#include "CMUXManager.h"
#include "CMUXChannel.h"
#include "ControlRequestHandler.h"

#define RECEIVE_AREA 4096

CMUXInstance::CMUXInstance(CMUXManager *parent, ControlRequestHandler *owner) :
  m_parent(parent), m_fd(-1), m_active(false), m_shutdown(false),
  m_recvBuf(RECEIVE_AREA), m_owner(owner) {

  gsm0710_initialize(&m_ctx);

  m_ctx.user_data = this;
  m_ctx.read = CMUXInstance::gsm0710_read;
  m_ctx.write = CMUXInstance::gsm0710_write;
  m_ctx.deliver_data = CMUXInstance::gsm0710_deliver_data;
  m_ctx.deliver_status = CMUXInstance::gsm0710_deliver_status;
  m_ctx.debug_message = CMUXInstance::gsm0710_debug_message;
  m_ctx.open_channel = CMUXInstance::gsm0710_open_channel;
  m_ctx.close_channel = CMUXInstance::gsm0710_close_channel;
  m_ctx.terminate = CMUXInstance::gsm0710_terminate;
}

CMUXInstance::~CMUXInstance() {
  if(m_owner)
    m_owner->multiplexerTerminated();

  if(m_active) {
    m_parent->uninstallWatcher(this);
  }

  for(unsigned int i = 0; i < m_channels.size(); i++) {
    CMUXChannel *channel = m_channels[i];

    if(channel) {
      m_parent->uninstallWatcher(channel);
      delete channel;
    }
  }

  if(m_fd != -1) {
    syslog(LOG_INFO, "%p: closed", this);
    close(m_fd);
  }
}

void CMUXInstance::shutdown() {
  m_owner = 0;

  if(!m_active)
    delete this;
  else {
    syslog(LOG_INFO, "%p: shutting down", this);

    m_shutdown = true;
    gsm0710_shutdown(&m_ctx);
  }
}

void CMUXInstance::open(const std::string &device) {
  char *error;
  m_fd = cmux_open_device(device.c_str(), &error);
  if(m_fd == -1) {
    std::string err_str = error;
    free(error);

    throw std::runtime_error(err_str);
  }

  syslog(LOG_INFO, "%p: open %s", this, device.c_str());
}

void CMUXInstance::activate() {
  if(m_fd == -1)
    throw std::runtime_error("device is not open yet");

  if(m_active)
    throw std::runtime_error("device is already activated");

  m_parent->installWatcher(this);
  m_active = true;

  syslog(LOG_INFO, "%p: activated", this);

  gsm0710_startup(&m_ctx, 0);
}

std::string CMUXInstance::openPort(int port, uid_t owner) {
  if(!m_active)
    throw std::runtime_error("device is not activated yet");

  if(!::gsm0710_open_channel(&m_ctx, port))
    throw std::runtime_error("channel is unavailable");

  doOpenChannel(port);

  CMUXChannel *channel = m_channels[port];

  chmod(channel->device().c_str(), 0600);
  chown(channel->device().c_str(), owner, 0);

  return channel->device();
}

void CMUXInstance::closePort(int port) {
  doCloseChannel(port);

  gsm0710_close_channel(&m_ctx, port);
}

void CMUXInstance::doOpenChannel(int port) {
  if(m_channels.size() <= (unsigned int) port)
    m_channels.resize(port + 1, 0);

  CMUXChannel *channel = m_channels[port];
  if(channel == NULL) {
    channel = new CMUXChannel(this, port);
    m_parent->installWatcher(channel);
    m_channels[port] = channel;
  }
}

void CMUXInstance::doCloseChannel(int port) {
  if(m_channels.size() <= (unsigned int) port)
    m_channels.resize(port + 1, 0);

  CMUXChannel *channel = m_channels[port];
  if(channel != NULL) {
    m_parent->uninstallWatcher(channel);
    delete channel;
    m_channels[port] = 0;
  }
}

int CMUXInstance::fd() const {
  return m_fd;
}

bool CMUXInstance::wantsRead() const {
  return true;
}

bool CMUXInstance::wantsWrite() const {
  return !m_sendBuf.empty();
}

void CMUXInstance::readable() {
  size_t size = m_recvBuf.size();

  ssize_t bytes = read(m_fd, &m_recvBuf[size - RECEIVE_AREA], RECEIVE_AREA);

  if(bytes == 0) {
    delete this;

    return;
  }

  if(bytes == -1 && errno == EWOULDBLOCK)
    return;

  if(bytes == -1) {
    delete this;

    return;
  }

  size_t usedBytes = size + bytes - RECEIVE_AREA;
  m_recvBuf.resize(usedBytes + RECEIVE_AREA);

  gsm0710_ready_read(&m_ctx);
}

void CMUXInstance::writable() {
  int bytes = write(m_fd, &m_sendBuf[0], m_sendBuf.size());
  if(bytes == -1 && errno == EAGAIN)
    return;

  if(bytes == -1) {
    delete this;

    return;
  }

  m_sendBuf.erase(m_sendBuf.begin(), m_sendBuf.begin() + bytes);

  if(m_shutdown && m_sendBuf.empty()) {
    delete this;
  }
}

void CMUXInstance::abnormal() {
  delete this;
}

void CMUXInstance::deliverToChannel(int id, const void *data, size_t len) {
  gsm0710_write_data(&m_ctx, id, data, len);
}

int CMUXInstance::gsm0710_read(struct gsm0710_context *ctx,
                               void *data, int len) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  int bytes = std::min<int>(instance->m_recvBuf.size() - RECEIVE_AREA, len);
  std::copy(instance->m_recvBuf.begin(),
            instance->m_recvBuf.begin() + bytes,
            (char *) data);
  instance->m_recvBuf.erase(instance->m_recvBuf.begin(),
                            instance->m_recvBuf.begin() + bytes);

  return bytes;

}

int CMUXInstance::gsm0710_write(struct gsm0710_context *ctx, const void *data,
                                int len) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  instance->m_sendBuf.resize(instance->m_sendBuf.size() + len);
  std::copy((char *) data, (char *) data + len,
            instance->m_sendBuf.end() - len);

  return len;
}

void CMUXInstance::gsm0710_deliver_data(struct gsm0710_context *ctx, int port,
                                        const void *data, int len) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  CMUXChannel *channel;

  if((unsigned int) port < instance->m_channels.size())
    channel = instance->m_channels[port];
  else
    channel = 0;

  if(channel == 0) {
    syslog(LOG_WARNING, "%p: attempted to deliver data to nonexistent channel %d. Client died unexpectedly?",
        instance, port);

    return;
  }

  channel->deliverToChannel(data, len);
}

void CMUXInstance::gsm0710_deliver_status(struct gsm0710_context *ctx, int channel,
                                          int status) {

  (void) ctx;
  (void) channel;
  (void) status;

  /*
   * TODO: deliver line status
   *
   * In theory, we could emulate serial events like CD/DSR drop on PTY,
   * but it will require duplication of a huge chunk of a kernel logic here and
   * it's not strictly necessary for pppd.
   */
}

void CMUXInstance::gsm0710_debug_message(struct gsm0710_context *ctx,
                                         const char *msg) {

  (void) ctx;

  syslog(LOG_DEBUG, "gsm0710: %s", msg);
}

void CMUXInstance::gsm0710_open_channel(struct gsm0710_context *ctx,
                                        int port) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  try {
    instance->doOpenChannel(port);
  } catch(std::exception &e) {
    syslog(LOG_WARNING, "device requested initiation of port %d, but attempt to do that failed: %s",
           port, e.what());
  }
}

void CMUXInstance::gsm0710_close_channel(struct gsm0710_context *ctx,
                                         int port) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  try {
    instance->doCloseChannel(port);
  } catch(std::exception &e) {
    syslog(LOG_WARNING, "device requested termination of port %d, but attempt to do that failed: %s",
           port, e.what());
  }
}

void CMUXInstance::gsm0710_terminate(struct gsm0710_context *ctx) {
  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  delete instance;
}
<commit_msg>Raise and drop DTR for channels.<commit_after>#include <cmux/c_api.h>
#include <stdexcept>

#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include "CMUXInstance.h"
#include "CMUXManager.h"
#include "CMUXChannel.h"
#include "ControlRequestHandler.h"

#define RECEIVE_AREA 4096

CMUXInstance::CMUXInstance(CMUXManager *parent, ControlRequestHandler *owner) :
  m_parent(parent), m_fd(-1), m_active(false), m_shutdown(false),
  m_recvBuf(RECEIVE_AREA), m_owner(owner) {

  gsm0710_initialize(&m_ctx);

  m_ctx.user_data = this;
  m_ctx.read = CMUXInstance::gsm0710_read;
  m_ctx.write = CMUXInstance::gsm0710_write;
  m_ctx.deliver_data = CMUXInstance::gsm0710_deliver_data;
  m_ctx.deliver_status = CMUXInstance::gsm0710_deliver_status;
  m_ctx.debug_message = CMUXInstance::gsm0710_debug_message;
  m_ctx.open_channel = CMUXInstance::gsm0710_open_channel;
  m_ctx.close_channel = CMUXInstance::gsm0710_close_channel;
  m_ctx.terminate = CMUXInstance::gsm0710_terminate;
}

CMUXInstance::~CMUXInstance() {
  if(m_owner)
    m_owner->multiplexerTerminated();

  if(m_active) {
    m_parent->uninstallWatcher(this);
  }

  for(unsigned int i = 0; i < m_channels.size(); i++) {
    CMUXChannel *channel = m_channels[i];

    if(channel) {
      m_parent->uninstallWatcher(channel);
      delete channel;
    }
  }

  if(m_fd != -1) {
    syslog(LOG_INFO, "%p: closed", this);
    close(m_fd);
  }
}

void CMUXInstance::shutdown() {
  m_owner = 0;

  if(!m_active)
    delete this;
  else {
    syslog(LOG_INFO, "%p: shutting down", this);

    m_shutdown = true;
    gsm0710_shutdown(&m_ctx);
  }
}

void CMUXInstance::open(const std::string &device) {
  char *error;
  m_fd = cmux_open_device(device.c_str(), &error);
  if(m_fd == -1) {
    std::string err_str = error;
    free(error);

    throw std::runtime_error(err_str);
  }

  syslog(LOG_INFO, "%p: open %s", this, device.c_str());
}

void CMUXInstance::activate() {
  if(m_fd == -1)
    throw std::runtime_error("device is not open yet");

  if(m_active)
    throw std::runtime_error("device is already activated");

  m_parent->installWatcher(this);
  m_active = true;

  syslog(LOG_INFO, "%p: activated", this);

  gsm0710_startup(&m_ctx, 0);
}

std::string CMUXInstance::openPort(int port, uid_t owner) {
  if(!m_active)
    throw std::runtime_error("device is not activated yet");

  if(!::gsm0710_open_channel(&m_ctx, port))
    throw std::runtime_error("channel is unavailable");

  doOpenChannel(port);

  CMUXChannel *channel = m_channels[port];

  chmod(channel->device().c_str(), 0600);
  chown(channel->device().c_str(), owner, 0);

  return channel->device();
}

void CMUXInstance::closePort(int port) {
  doCloseChannel(port);

  gsm0710_close_channel(&m_ctx, port);
}

void CMUXInstance::doOpenChannel(int port) {
  if(m_channels.size() <= (unsigned int) port)
    m_channels.resize(port + 1, 0);

  CMUXChannel *channel = m_channels[port];
  if(channel == NULL) {
    channel = new CMUXChannel(this, port);
    m_parent->installWatcher(channel);
    m_channels[port] = channel;
  }

  gsm0710_set_status(&m_ctx, port, GSM0710_DTR | GSM0710_RTS | GSM0710_FC);
}

void CMUXInstance::doCloseChannel(int port) {
  gsm0710_set_status(&m_ctx, port, GSM0710_RTS | GSM0710_FC);

  if(m_channels.size() <= (unsigned int) port)
    m_channels.resize(port + 1, 0);

  CMUXChannel *channel = m_channels[port];
  if(channel != NULL) {
    m_parent->uninstallWatcher(channel);
    delete channel;
    m_channels[port] = 0;
  }
}

int CMUXInstance::fd() const {
  return m_fd;
}

bool CMUXInstance::wantsRead() const {
  return true;
}

bool CMUXInstance::wantsWrite() const {
  return !m_sendBuf.empty();
}

void CMUXInstance::readable() {
  size_t size = m_recvBuf.size();

  ssize_t bytes = read(m_fd, &m_recvBuf[size - RECEIVE_AREA], RECEIVE_AREA);

  if(bytes == 0) {
    delete this;

    return;
  }

  if(bytes == -1 && errno == EWOULDBLOCK)
    return;

  if(bytes == -1) {
    delete this;

    return;
  }

  size_t usedBytes = size + bytes - RECEIVE_AREA;
  m_recvBuf.resize(usedBytes + RECEIVE_AREA);

  gsm0710_ready_read(&m_ctx);
}

void CMUXInstance::writable() {
  int bytes = write(m_fd, &m_sendBuf[0], m_sendBuf.size());
  if(bytes == -1 && errno == EAGAIN)
    return;

  if(bytes == -1) {
    delete this;

    return;
  }

  m_sendBuf.erase(m_sendBuf.begin(), m_sendBuf.begin() + bytes);

  if(m_shutdown && m_sendBuf.empty()) {
    delete this;
  }
}

void CMUXInstance::abnormal() {
  delete this;
}

void CMUXInstance::deliverToChannel(int id, const void *data, size_t len) {
  gsm0710_write_data(&m_ctx, id, data, len);
}

int CMUXInstance::gsm0710_read(struct gsm0710_context *ctx,
                               void *data, int len) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  int bytes = std::min<int>(instance->m_recvBuf.size() - RECEIVE_AREA, len);
  std::copy(instance->m_recvBuf.begin(),
            instance->m_recvBuf.begin() + bytes,
            (char *) data);
  instance->m_recvBuf.erase(instance->m_recvBuf.begin(),
                            instance->m_recvBuf.begin() + bytes);

  return bytes;

}

int CMUXInstance::gsm0710_write(struct gsm0710_context *ctx, const void *data,
                                int len) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  instance->m_sendBuf.resize(instance->m_sendBuf.size() + len);
  std::copy((char *) data, (char *) data + len,
            instance->m_sendBuf.end() - len);

  return len;
}

void CMUXInstance::gsm0710_deliver_data(struct gsm0710_context *ctx, int port,
                                        const void *data, int len) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  CMUXChannel *channel;

  if((unsigned int) port < instance->m_channels.size())
    channel = instance->m_channels[port];
  else
    channel = 0;

  if(channel == 0) {
    syslog(LOG_WARNING, "%p: attempted to deliver data to nonexistent channel %d. Client died unexpectedly?",
        instance, port);

    return;
  }

  channel->deliverToChannel(data, len);
}

void CMUXInstance::gsm0710_deliver_status(struct gsm0710_context *ctx, int channel,
                                          int status) {

  (void) ctx;
  (void) channel;
  (void) status;

  /*
   * TODO: deliver line status
   *
   * In theory, we could emulate serial events like CD/DSR drop on PTY,
   * but it will require duplication of a huge chunk of a kernel logic here and
   * it's not strictly necessary for pppd.
   */
}

void CMUXInstance::gsm0710_debug_message(struct gsm0710_context *ctx,
                                         const char *msg) {

  (void) ctx;

  syslog(LOG_DEBUG, "gsm0710: %s", msg);
}

void CMUXInstance::gsm0710_open_channel(struct gsm0710_context *ctx,
                                        int port) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  try {
    instance->doOpenChannel(port);
  } catch(std::exception &e) {
    syslog(LOG_WARNING, "device requested initiation of port %d, but attempt to do that failed: %s",
           port, e.what());
  }
}

void CMUXInstance::gsm0710_close_channel(struct gsm0710_context *ctx,
                                         int port) {

  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  try {
    instance->doCloseChannel(port);
  } catch(std::exception &e) {
    syslog(LOG_WARNING, "device requested termination of port %d, but attempt to do that failed: %s",
           port, e.what());
  }
}

void CMUXInstance::gsm0710_terminate(struct gsm0710_context *ctx) {
  CMUXInstance *instance = static_cast<CMUXInstance *>(ctx->user_data);

  delete instance;
}
<|endoftext|>


<commit_before>//===- llvm-objcopy.cpp ---------------------------------------------------===//
//
//                      The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm-objcopy.h"
#include "Buffer.h"
#include "CopyConfig.h"
#include "ELF/ELFObjcopy.h"

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <memory>
#include <string>
#include <system_error>
#include <utility>

namespace llvm {
namespace objcopy {

// The name this program was invoked as.
StringRef ToolName;

LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
  WithColor::error(errs(), ToolName) << Message << ".\n";
  errs().flush();
  exit(1);
}

LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
  assert(EC);
  WithColor::error(errs(), ToolName)
      << "'" << File << "': " << EC.message() << ".\n";
  exit(1);
}

LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
  assert(E);
  std::string Buf;
  raw_string_ostream OS(Buf);
  logAllUnhandledErrors(std::move(E), OS, "");
  OS.flush();
  WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
  exit(1);
}

} // end namespace objcopy
} // end namespace llvm

using namespace llvm;
using namespace llvm::object;
using namespace llvm::objcopy;

// For regular archives this function simply calls llvm::writeArchive,
// For thin archives it writes the archive file itself as well as its members.
static Error deepWriteArchive(StringRef ArcName,
                              ArrayRef<NewArchiveMember> NewMembers,
                              bool WriteSymtab, object::Archive::Kind Kind,
                              bool Deterministic, bool Thin) {
  Error E =
      writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
  if (!Thin || E)
    return E;
  for (const NewArchiveMember &Member : NewMembers) {
    // Internally, FileBuffer will use the buffer created by
    // FileOutputBuffer::create, for regular files (that is the case for
    // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
    // OnDiskBuffer uses a temporary file and then renames it. So in reality
    // there is no inefficiency / duplicated in-memory buffers in this case. For
    // now in-memory buffers can not be completely avoided since
    // NewArchiveMember still requires them even though writeArchive does not
    // write them on disk.
    FileBuffer FB(Member.MemberName);
    FB.allocate(Member.Buf->getBufferSize());
    std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
              FB.getBufferStart());
    if (auto E = FB.commit())
      return E;
  }
  return Error::success();
}

/// The function executeObjcopyOnRawBinary does the dispatch based on the format
/// of the output specified by the command line options.
static void executeObjcopyOnRawBinary(const CopyConfig &Config,
                                      MemoryBuffer &In, Buffer &Out) {
  // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize
  // formats other than ELF / "binary" and invoke
  // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or
  // coff::executeObjcopyOnRawBinary accordingly.
  return elf::executeObjcopyOnRawBinary(Config, In, Out);
}

/// The function executeObjcopyOnBinary does the dispatch based on the format
/// of the input binary (ELF, MachO or COFF).
static void executeObjcopyOnBinary(const CopyConfig &Config, object::Binary &In,
                                   Buffer &Out) {
  if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In))
    return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
  else
    error("Unsupported object file format");
}

static void executeObjcopyOnArchive(const CopyConfig &Config,
                                    const Archive &Ar) {
  std::vector<NewArchiveMember> NewArchiveMembers;
  Error Err = Error::success();
  for (const Archive::Child &Child : Ar.children(Err)) {
    Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
    if (!ChildOrErr)
      reportError(Ar.getFileName(), ChildOrErr.takeError());
    Binary *Bin = ChildOrErr->get();

    Expected<StringRef> ChildNameOrErr = Child.getName();
    if (!ChildNameOrErr)
      reportError(Ar.getFileName(), ChildNameOrErr.takeError());

    MemBuffer MB(ChildNameOrErr.get());
    executeObjcopyOnBinary(Config, *Bin, MB);

    Expected<NewArchiveMember> Member =
        NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
    if (!Member)
      reportError(Ar.getFileName(), Member.takeError());
    Member->Buf = MB.releaseMemoryBuffer();
    Member->MemberName = Member->Buf->getBufferIdentifier();
    NewArchiveMembers.push_back(std::move(*Member));
  }

  if (Err)
    reportError(Config.InputFilename, std::move(Err));
  if (Error E = deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
                                 Ar.hasSymbolTable(), Ar.kind(),
                                 Config.DeterministicArchives, Ar.isThin()))
    reportError(Config.OutputFilename, std::move(E));
}

static void restoreDateOnFile(StringRef Filename,
                              const sys::fs::file_status &Stat) {
  int FD;

  if (auto EC =
          sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
    reportError(Filename, EC);

  if (auto EC = sys::fs::setLastAccessAndModificationTime(
          FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
    reportError(Filename, EC);

  if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
    reportError(Filename, EC);
}

/// The function executeObjcopy does the higher level dispatch based on the type
/// of input (raw binary, archive or single object file) and takes care of the
/// format-agnostic modifications, i.e. preserving dates.
static void executeObjcopy(const CopyConfig &Config) {
  sys::fs::file_status Stat;
  if (Config.PreserveDates)
    if (auto EC = sys::fs::status(Config.InputFilename, Stat))
      reportError(Config.InputFilename, EC);

  if (Config.InputFormat == "binary") {
    auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
    if (!BufOrErr)
      reportError(Config.InputFilename, BufOrErr.getError());
    FileBuffer FB(Config.OutputFilename);
    executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB);
  } else {
    Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
        createBinary(Config.InputFilename);
    if (!BinaryOrErr)
      reportError(Config.InputFilename, BinaryOrErr.takeError());

    if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
      executeObjcopyOnArchive(Config, *Ar);
    } else {
      FileBuffer FB(Config.OutputFilename);
      executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
    }
  }

  if (Config.PreserveDates) {
    restoreDateOnFile(Config.OutputFilename, Stat);
    if (!Config.SplitDWO.empty())
      restoreDateOnFile(Config.SplitDWO, Stat);
  }
}

int main(int argc, char **argv) {
  InitLLVM X(argc, argv);
  ToolName = argv[0];
  DriverConfig DriverConfig;
  if (sys::path::stem(ToolName).endswith_lower("strip"))
    DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
  else
    DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
  for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
    executeObjcopy(CopyConfig);
}
<commit_msg>[llvm-strip] Check "strip" with StringRef::contains instead of ends_with<commit_after>//===- llvm-objcopy.cpp ---------------------------------------------------===//
//
//                      The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm-objcopy.h"
#include "Buffer.h"
#include "CopyConfig.h"
#include "ELF/ELFObjcopy.h"

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <memory>
#include <string>
#include <system_error>
#include <utility>

namespace llvm {
namespace objcopy {

// The name this program was invoked as.
StringRef ToolName;

LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
  WithColor::error(errs(), ToolName) << Message << ".\n";
  errs().flush();
  exit(1);
}

LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
  assert(EC);
  WithColor::error(errs(), ToolName)
      << "'" << File << "': " << EC.message() << ".\n";
  exit(1);
}

LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
  assert(E);
  std::string Buf;
  raw_string_ostream OS(Buf);
  logAllUnhandledErrors(std::move(E), OS, "");
  OS.flush();
  WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
  exit(1);
}

} // end namespace objcopy
} // end namespace llvm

using namespace llvm;
using namespace llvm::object;
using namespace llvm::objcopy;

// For regular archives this function simply calls llvm::writeArchive,
// For thin archives it writes the archive file itself as well as its members.
static Error deepWriteArchive(StringRef ArcName,
                              ArrayRef<NewArchiveMember> NewMembers,
                              bool WriteSymtab, object::Archive::Kind Kind,
                              bool Deterministic, bool Thin) {
  Error E =
      writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
  if (!Thin || E)
    return E;
  for (const NewArchiveMember &Member : NewMembers) {
    // Internally, FileBuffer will use the buffer created by
    // FileOutputBuffer::create, for regular files (that is the case for
    // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
    // OnDiskBuffer uses a temporary file and then renames it. So in reality
    // there is no inefficiency / duplicated in-memory buffers in this case. For
    // now in-memory buffers can not be completely avoided since
    // NewArchiveMember still requires them even though writeArchive does not
    // write them on disk.
    FileBuffer FB(Member.MemberName);
    FB.allocate(Member.Buf->getBufferSize());
    std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
              FB.getBufferStart());
    if (auto E = FB.commit())
      return E;
  }
  return Error::success();
}

/// The function executeObjcopyOnRawBinary does the dispatch based on the format
/// of the output specified by the command line options.
static void executeObjcopyOnRawBinary(const CopyConfig &Config,
                                      MemoryBuffer &In, Buffer &Out) {
  // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize
  // formats other than ELF / "binary" and invoke
  // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or
  // coff::executeObjcopyOnRawBinary accordingly.
  return elf::executeObjcopyOnRawBinary(Config, In, Out);
}

/// The function executeObjcopyOnBinary does the dispatch based on the format
/// of the input binary (ELF, MachO or COFF).
static void executeObjcopyOnBinary(const CopyConfig &Config, object::Binary &In,
                                   Buffer &Out) {
  if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In))
    return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
  else
    error("Unsupported object file format");
}

static void executeObjcopyOnArchive(const CopyConfig &Config,
                                    const Archive &Ar) {
  std::vector<NewArchiveMember> NewArchiveMembers;
  Error Err = Error::success();
  for (const Archive::Child &Child : Ar.children(Err)) {
    Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
    if (!ChildOrErr)
      reportError(Ar.getFileName(), ChildOrErr.takeError());
    Binary *Bin = ChildOrErr->get();

    Expected<StringRef> ChildNameOrErr = Child.getName();
    if (!ChildNameOrErr)
      reportError(Ar.getFileName(), ChildNameOrErr.takeError());

    MemBuffer MB(ChildNameOrErr.get());
    executeObjcopyOnBinary(Config, *Bin, MB);

    Expected<NewArchiveMember> Member =
        NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
    if (!Member)
      reportError(Ar.getFileName(), Member.takeError());
    Member->Buf = MB.releaseMemoryBuffer();
    Member->MemberName = Member->Buf->getBufferIdentifier();
    NewArchiveMembers.push_back(std::move(*Member));
  }

  if (Err)
    reportError(Config.InputFilename, std::move(Err));
  if (Error E = deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
                                 Ar.hasSymbolTable(), Ar.kind(),
                                 Config.DeterministicArchives, Ar.isThin()))
    reportError(Config.OutputFilename, std::move(E));
}

static void restoreDateOnFile(StringRef Filename,
                              const sys::fs::file_status &Stat) {
  int FD;

  if (auto EC =
          sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
    reportError(Filename, EC);

  if (auto EC = sys::fs::setLastAccessAndModificationTime(
          FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
    reportError(Filename, EC);

  if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
    reportError(Filename, EC);
}

/// The function executeObjcopy does the higher level dispatch based on the type
/// of input (raw binary, archive or single object file) and takes care of the
/// format-agnostic modifications, i.e. preserving dates.
static void executeObjcopy(const CopyConfig &Config) {
  sys::fs::file_status Stat;
  if (Config.PreserveDates)
    if (auto EC = sys::fs::status(Config.InputFilename, Stat))
      reportError(Config.InputFilename, EC);

  if (Config.InputFormat == "binary") {
    auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
    if (!BufOrErr)
      reportError(Config.InputFilename, BufOrErr.getError());
    FileBuffer FB(Config.OutputFilename);
    executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB);
  } else {
    Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
        createBinary(Config.InputFilename);
    if (!BinaryOrErr)
      reportError(Config.InputFilename, BinaryOrErr.takeError());

    if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
      executeObjcopyOnArchive(Config, *Ar);
    } else {
      FileBuffer FB(Config.OutputFilename);
      executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
    }
  }

  if (Config.PreserveDates) {
    restoreDateOnFile(Config.OutputFilename, Stat);
    if (!Config.SplitDWO.empty())
      restoreDateOnFile(Config.SplitDWO, Stat);
  }
}

int main(int argc, char **argv) {
  InitLLVM X(argc, argv);
  ToolName = argv[0];
  DriverConfig DriverConfig;
  if (sys::path::stem(ToolName).contains("strip"))
    DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
  else
    DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
  for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
    executeObjcopy(CopyConfig);
}
<|endoftext|>