<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: navigationbar.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 12:55:47 $
 *
 *  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
 *
 ************************************************************************/

#ifndef FORMS_COMPONENT_NAVIGATION_BAR_HXX
#define FORMS_COMPONENT_NAVIGATION_BAR_HXX

#ifndef _FORMS_FORMCOMPONENT_HXX_
#include "FormComponent.hxx"
#endif

#ifndef _COM_SUN_STAR_IO_XPERSISTOBJECT_HPP_
#include <com/sun/star/io/XPersistObject.hpp>
#endif
#ifndef _COMPHELPER_PROPERTY_ARRAY_HELPER_HXX_
#include <comphelper/proparrhlp.hxx>
#endif
#ifndef COMPHELPER_PROPERTYCONTAINERHELPER_HXX
#include <comphelper/propertycontainerhelper.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _CPPUHELPER_INTERFACECONTAINER_HXX_
#include <cppuhelper/interfacecontainer.hxx>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XSET_HPP_
#include <com/sun/star/container/XSet.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XCONTAINER_HPP_
#include <com/sun/star/container/XContainer.hpp>
#endif
#ifndef FORMS_SOURCE_COMPONENT_FORMCONTROLFONT_HXX
#include "formcontrolfont.hxx"
#endif

#include <set>

//.........................................................................
namespace frm
{
//.........................................................................

    //==================================================================
    // ONavigationBarModel
    //==================================================================
    typedef ::cppu::ImplHelper1 <   ::com::sun::star::awt::XControlModel
                                > ONavigationBarModel_BASE;

    class ONavigationBarModel
                        :public OControlModel
                        ,public FontControlModel
                        ,public OPropertyContainerHelper
                        ,public OAggregationArrayUsageHelper< ONavigationBarModel >
                            // though we don't use aggregation, we're derived from an OPropertySetAggregationHelper,
                            // which expects that we use an OPropertyArrayAggregationHelper, which we ensure
                            // with deriving from OAggregationArrayUsageHelper
                        ,public ONavigationBarModel_BASE
    {
        // <properties>
        ::com::sun::star::uno::Any          m_aTabStop;
        ::com::sun::star::uno::Any          m_aBackgroundColor;
        ::rtl::OUString                     m_sDefaultControl;
        ::rtl::OUString                     m_sHelpText;
        ::rtl::OUString                     m_sHelpURL;
        sal_Int16                           m_nIconSize;
        sal_Int16                           m_nBorder;
        sal_Int32                           m_nDelay;
        sal_Bool                            m_bEnabled;
        sal_Bool                            m_bShowPosition;
        sal_Bool                            m_bShowNavigation;
        sal_Bool                            m_bShowActions;
        sal_Bool                            m_bShowFilterSort;
        // </properties>

    public:
        DECLARE_DEFAULT_LEAF_XTOR( ONavigationBarModel );

        // XServiceInfo - static version
        static  ::rtl::OUString SAL_CALL getImplementationName_Static();
        static  ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_Static();
        static  ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Create( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory );

    protected:
        // UNO
        DECLARE_UNO3_AGG_DEFAULTS( ONavigationBarModel, OControlModel );
        virtual ::com::sun::star::uno::Any SAL_CALL queryAggregation( const ::com::sun::star::uno::Type& _rType ) throw (::com::sun::star::uno::RuntimeException);

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName()  throw(::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()  throw(::com::sun::star::uno::RuntimeException);

        // XTypeProvider
        DECLARE_XTYPEPROVIDER()

        // OComponentHelper
        virtual void SAL_CALL disposing();

        // XPersistObject
        virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL write(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL read(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

        // XPropertySet
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() throw(::com::sun::star::uno::RuntimeException);
        virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();
        virtual void SAL_CALL getFastPropertyValue(::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const;
        virtual sal_Bool SAL_CALL convertFastPropertyValue(::com::sun::star::uno::Any& rConvertedValue, ::com::sun::star::uno::Any& rOldValue,
                                              sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue )
                                            throw(::com::sun::star::lang::IllegalArgumentException);
        virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue) throw ( ::com::sun::star::uno::Exception);

        // XPropertyState
        virtual ::com::sun::star::uno::Any getPropertyDefaultByHandle( sal_Int32 nHandle ) const;

        // OAggregationArrayUsageHelper
        virtual void fillProperties(
            ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps,
            ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rAggregateProps
            ) const;
        IMPLEMENT_INFO_SERVICE()

        // prevent method hiding
        using OControlModel::disposing;
        using OControlModel::getFastPropertyValue;

    protected:
        DECLARE_XCLONEABLE();

    private:
        void implInitPropertyContainer();
    };

//.........................................................................
}   // namespace frm
//.........................................................................

#endif // FORMS_COMPONENT_NAVIGATION_BAR_HXX

<commit_msg>INTEGRATION: CWS hb02 (1.4.80); FILE MERGED 2007/02/01 12:09:41 fs 1.4.80.2: #i74051# split describeFixedProperties in describeFixedProperties and describeAggregateProperties 2007/01/31 10:55:30 fs 1.4.80.1: changed handling of properties in the course of #i74051#<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: navigationbar.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2007-03-09 13:33:37 $
 *
 *  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
 *
 ************************************************************************/

#ifndef FORMS_COMPONENT_NAVIGATION_BAR_HXX
#define FORMS_COMPONENT_NAVIGATION_BAR_HXX

#ifndef _FORMS_FORMCOMPONENT_HXX_
#include "FormComponent.hxx"
#endif

#ifndef _COM_SUN_STAR_IO_XPERSISTOBJECT_HPP_
#include <com/sun/star/io/XPersistObject.hpp>
#endif
#ifndef _COMPHELPER_PROPERTY_ARRAY_HELPER_HXX_
#include <comphelper/proparrhlp.hxx>
#endif
#ifndef COMPHELPER_PROPERTYCONTAINERHELPER_HXX
#include <comphelper/propertycontainerhelper.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _CPPUHELPER_INTERFACECONTAINER_HXX_
#include <cppuhelper/interfacecontainer.hxx>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XSET_HPP_
#include <com/sun/star/container/XSet.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XCONTAINER_HPP_
#include <com/sun/star/container/XContainer.hpp>
#endif
#ifndef FORMS_SOURCE_COMPONENT_FORMCONTROLFONT_HXX
#include "formcontrolfont.hxx"
#endif

#include <set>

//.........................................................................
namespace frm
{
//.........................................................................

    //==================================================================
    // ONavigationBarModel
    //==================================================================
    typedef ::cppu::ImplHelper1 <   ::com::sun::star::awt::XControlModel
                                > ONavigationBarModel_BASE;

    class ONavigationBarModel
                        :public OControlModel
                        ,public FontControlModel
                        ,public OPropertyContainerHelper
                        ,public ONavigationBarModel_BASE
    {
        // <properties>
        ::com::sun::star::uno::Any          m_aTabStop;
        ::com::sun::star::uno::Any          m_aBackgroundColor;
        ::rtl::OUString                     m_sDefaultControl;
        ::rtl::OUString                     m_sHelpText;
        ::rtl::OUString                     m_sHelpURL;
        sal_Int16                           m_nIconSize;
        sal_Int16                           m_nBorder;
        sal_Int32                           m_nDelay;
        sal_Bool                            m_bEnabled;
        sal_Bool                            m_bShowPosition;
        sal_Bool                            m_bShowNavigation;
        sal_Bool                            m_bShowActions;
        sal_Bool                            m_bShowFilterSort;
        // </properties>

    public:
        DECLARE_DEFAULT_LEAF_XTOR( ONavigationBarModel );

        // XServiceInfo - static version
        static  ::rtl::OUString SAL_CALL getImplementationName_Static();
        static  ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_Static();
        static  ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Create( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory );

    protected:
        // UNO
        DECLARE_UNO3_AGG_DEFAULTS( ONavigationBarModel, OControlModel );
        virtual ::com::sun::star::uno::Any SAL_CALL queryAggregation( const ::com::sun::star::uno::Type& _rType ) throw (::com::sun::star::uno::RuntimeException);

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName()  throw(::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()  throw(::com::sun::star::uno::RuntimeException);

        // XTypeProvider
        DECLARE_XTYPEPROVIDER()

        // OComponentHelper
        virtual void SAL_CALL disposing();

        // XPersistObject
        virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL write(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL read(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

        // XPropertySet
        virtual void SAL_CALL getFastPropertyValue(::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const;
        virtual sal_Bool SAL_CALL convertFastPropertyValue(::com::sun::star::uno::Any& rConvertedValue, ::com::sun::star::uno::Any& rOldValue,
                                              sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue )
                                            throw(::com::sun::star::lang::IllegalArgumentException);
        virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue) throw ( ::com::sun::star::uno::Exception);

        // XPropertyState
        virtual ::com::sun::star::uno::Any getPropertyDefaultByHandle( sal_Int32 nHandle ) const;

        // OControlModel's property handling
        virtual void describeFixedProperties(
            ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps
        ) const;

        // prevent method hiding
        using OControlModel::disposing;
        using OControlModel::getFastPropertyValue;

    protected:
        DECLARE_XCLONEABLE();

    private:
        void implInitPropertyContainer();
    };

//.........................................................................
}   // namespace frm
//.........................................................................

#endif // FORMS_COMPONENT_NAVIGATION_BAR_HXX

<|endoftext|>


<commit_before>#include <algorithm>

#include "Vajra/Engine/Core/Engine.h"
#include "Vajra/Engine/Input/Input.h"
#include "Vajra/Utilities/Utilities.h"

#if PLATFORM_DESKTOP
// Global callback function for desktop input
void cursorPosCallback(int x, int y) {
	ENGINE->GetInput()->cursorPosUpdate(x, y);
}
#endif

Input::Input() {
}

Input::~Input() {
	this->destroy();
}

void Input::init() {
#if PLATFORM_DESKTOP
	glfwSetMousePosCallback(cursorPosCallback);
#endif
}

void Input::destroy() {
}

bool touchOver(const Touch &touch) {
	return (touch.phase == TouchPhase::Ended || touch.phase == TouchPhase::Cancelled);
}

void Input::updateInput() {
#if PLATFORM_DESKTOP
	this->updateMouseButton();
#endif
	// Populate frame touches with all input that has been asynchronously collected
	this->frameTouches = this->asyncTouches;

	// Remove all touches that have ended or been cancelled
	this->asyncTouches.erase( std::remove_if(this->asyncTouches.begin(), this->asyncTouches.end(), touchOver), this->asyncTouches.end());

	for(std::vector<Touch>::iterator it = this->asyncTouches.begin(); it != this->asyncTouches.end(); ++it) {
    	it->phase = TouchPhase::Stationary;
	}
	//logTouches();
}

Touch Input::GetTouch(int index) {
	ASSERT(index < this->frameTouches.size(), "Index is greater than current number of touches");
	return this->frameTouches[index];
}

void Input::AddTouch(int uId, float startX, float startY, TouchPhase phase) {
	Touch t;
	t.uId = uId;
	t.pos.x = startX;
	t.pos.y = startY;
	t.prevPos = t.pos;
	t.phase = phase;
	t.fingerId = this->asyncTouches.size();
	this->asyncTouches.push_back(t);
}

void Input::UpdateTouch(int uId, float curX, float curY, TouchPhase phase) {
	for(std::vector<Touch>::iterator it = this->asyncTouches.begin(); it != this->asyncTouches.end(); ++it) {
		if(it->uId == uId) {
			it->prevPos = it->pos;
			it->pos.x = curX;
			it->pos.y = curY;
			it->phase = phase;
			break;
		}
	}
}

void Input::logTouches() {
	FRAMEWORK->GetLogger()->dbglog("TOUCH LOG \n");
	for(std::vector<Touch>::iterator it = this->frameTouches.begin(); it != this->frameTouches.end(); ++it) {
		FRAMEWORK->GetLogger()->dbglog("Touch id: %i pos: (%f, %f) %i \n", it->fingerId, it->pos.x, it->pos.y, (int)it->phase);
	}
}

#if PLATFORM_DESKTOP
void Input::updateMouseButton() {
	// Grab the left click state and make it act like a single touch
	int button = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT);
	if(ENGINE->GetInput()->GetTouchCount() == 0) {
		if(button == 1) {
			ENGINE->GetInput()->AddTouch(0, this->mouseX, this->mouseY);
		}
	}
	else {
		if(button == 0) {
			ENGINE->GetInput()->UpdateTouch(0, this->mouseX, this->mouseY, TouchPhase::Ended);
		}
	}
}

void Input::cursorPosUpdate(int x, int y) {
	this->mouseX = x;
	this->mouseY = y;
	this->UpdateTouch(0, x, y, TouchPhase::Moved);
}
#endif
<commit_msg>Used GLFW enums instead of ints<commit_after>#include <algorithm>

#include "Vajra/Engine/Core/Engine.h"
#include "Vajra/Engine/Input/Input.h"
#include "Vajra/Utilities/Utilities.h"

#if PLATFORM_DESKTOP
// Global callback function for desktop input
void cursorPosCallback(int x, int y) {
	ENGINE->GetInput()->cursorPosUpdate(x, y);
}
#endif

Input::Input() {
}

Input::~Input() {
	this->destroy();
}

void Input::init() {
#if PLATFORM_DESKTOP
	glfwSetMousePosCallback(cursorPosCallback);
#endif
}

void Input::destroy() {
}

bool touchOver(const Touch &touch) {
	return (touch.phase == TouchPhase::Ended || touch.phase == TouchPhase::Cancelled);
}

void Input::updateInput() {
#if PLATFORM_DESKTOP
	this->updateMouseButton();
#endif
	// Populate frame touches with all input that has been asynchronously collected
	this->frameTouches = this->asyncTouches;

	// Remove all touches that have ended or been cancelled
	this->asyncTouches.erase( std::remove_if(this->asyncTouches.begin(), this->asyncTouches.end(), touchOver), this->asyncTouches.end());

	for(std::vector<Touch>::iterator it = this->asyncTouches.begin(); it != this->asyncTouches.end(); ++it) {
    	it->phase = TouchPhase::Stationary;
	}
	//logTouches();
}

Touch Input::GetTouch(int index) {
	ASSERT(index < this->frameTouches.size(), "Index is greater than current number of touches");
	return this->frameTouches[index];
}

void Input::AddTouch(int uId, float startX, float startY, TouchPhase phase) {
	Touch t;
	t.uId = uId;
	t.pos.x = startX;
	t.pos.y = startY;
	t.prevPos = t.pos;
	t.phase = phase;
	t.fingerId = this->asyncTouches.size();
	this->asyncTouches.push_back(t);
}

void Input::UpdateTouch(int uId, float curX, float curY, TouchPhase phase) {
	for(std::vector<Touch>::iterator it = this->asyncTouches.begin(); it != this->asyncTouches.end(); ++it) {
		if(it->uId == uId) {
			it->prevPos = it->pos;
			it->pos.x = curX;
			it->pos.y = curY;
			it->phase = phase;
			break;
		}
	}
}

void Input::logTouches() {
	FRAMEWORK->GetLogger()->dbglog("TOUCH LOG \n");
	for(std::vector<Touch>::iterator it = this->frameTouches.begin(); it != this->frameTouches.end(); ++it) {
		FRAMEWORK->GetLogger()->dbglog("Touch id: %i pos: (%f, %f) %i \n", it->fingerId, it->pos.x, it->pos.y, (int)it->phase);
	}
}

#if PLATFORM_DESKTOP
void Input::updateMouseButton() {
	// Grab the left click state and make it act like a single touch
	int button = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT);
	if(ENGINE->GetInput()->GetTouchCount() == 0) {
		if(button == GLFW_PRESS) {
			ENGINE->GetInput()->AddTouch(0, this->mouseX, this->mouseY);
		}
	}
	else {
		if(button == GLFW_RELEASE) {
			ENGINE->GetInput()->UpdateTouch(0, this->mouseX, this->mouseY, TouchPhase::Ended);
		}
	}
}

void Input::cursorPosUpdate(int x, int y) {
	this->mouseX = x;
	this->mouseY = y;
	this->UpdateTouch(0, x, y, TouchPhase::Moved);
}
#endif
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2022 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <lib/address_resolve/AddressResolve_DefaultImpl.h>

namespace chip {
namespace AddressResolve {
namespace Impl {
namespace {

static constexpr System::Clock::Timeout kInvalidTimeout{ System::Clock::Timeout::max() };

// IP addess "suitability"
//   - Larger value means "more suitable"
//   - Enum ordered ascending for easier read. Note however that order of
//     checks MUST match in ScoreIpAddress below.
enum class IpScore : unsigned
{
    kInvalid = 0, // No address available

    // "Other" IPv6 include:
    //   - invalid addresses (have seen router bugs during interop testing)
    //   - embedded IPv4 (::/80)
    kOtherIpv6                     = 1,
    kIpv4                          = 2, // Not Matter SPEC, so low priority
    kLinkLocal                     = 3, // Valid only on an interface
    kUniqueLocal                   = 4, // ULA. Thread devices use this
    kGlobalUnicast                 = 5, // Maybe routable, not local subnet
    kUniqueLocalWithSharedPrefix   = 6, // Prefix seems to match a local interface
    kGlobalUnicastWithSharedPrefix = 7, // Prefix seems to match a local interface
};

constexpr unsigned ScoreValue(IpScore score)
{
    return static_cast<unsigned>(score);
}

/**
 * Gives a score for an IP address, generally related to "how good" the address
 * is and how likely it is for it to be reachable.
 */
IpScore ScoreIpAddress(const Inet::IPAddress & ip, Inet::InterfaceId interfaceId)
{
    if (ip.IsIPv6())
    {
        if (interfaceId.MatchLocalIPv6Subnet(ip))
        {
            if (ip.IsIPv6GlobalUnicast())
            {
                return IpScore::kGlobalUnicastWithSharedPrefix;
            }
            if (ip.IsIPv6ULA())
            {
                return IpScore::kUniqueLocalWithSharedPrefix;
            }
        }
        if (ip.IsIPv6GlobalUnicast())
        {
            return IpScore::kGlobalUnicast;
        }

        if (ip.IsIPv6ULA())
        {
            return IpScore::kUniqueLocal;
        }

        if (ip.IsIPv6LinkLocal())
        {
            return IpScore::kLinkLocal;
        }

        return IpScore::kOtherIpv6;
    }

    return IpScore::kIpv4;
}

} // namespace

void NodeLookupHandle::ResetForLookup(System::Clock::Timestamp now, const NodeLookupRequest & request)
{
    mRequestStartTime = now;
    mRequest          = request;
    mBestResult       = ResolveResult();
    mBestAddressScore = ScoreValue(IpScore::kInvalid);
}

void NodeLookupHandle::LookupResult(const ResolveResult & result)
{
#if CHIP_PROGRESS_LOGGING
    char addr_string[Transport::PeerAddress::kMaxToStringSize];
    result.address.ToString(addr_string);
#endif

    unsigned newScore = ScoreValue(ScoreIpAddress(result.address.GetIPAddress(), result.address.GetInterface()));
    if (newScore > mBestAddressScore)
    {
        mBestResult       = result;
        mBestAddressScore = newScore;

        if (!mBestResult.address.GetIPAddress().IsIPv6LinkLocal())
        {
            // Only use the DNS-SD resolution's InterfaceID for addresses that are IPv6 LLA.
            // For all other addresses, we should rely on the device's routing table to route messages sent.
            // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread,
            // mDNS advertisements are not usually received on the same interface the peer is reachable on.
            mBestResult.address.SetInterface(Inet::InterfaceId::Null());
            ChipLogDetail(Discovery, "Lookup clearing interface for non LL address");
        }

#if CHIP_PROGRESS_LOGGING
        ChipLogProgress(Discovery, "%s: new best score: %u", addr_string, mBestAddressScore);
    }
    else
    {
        ChipLogProgress(Discovery, "%s: score has not improved: %u", addr_string, newScore);
#endif
    }
}

System::Clock::Timeout NodeLookupHandle::NextEventTimeout(System::Clock::Timestamp now)
{
    const System::Clock::Timestamp elapsed = now - mRequestStartTime;

    if (elapsed < mRequest.GetMinLookupTime())
    {
        return mRequest.GetMinLookupTime() - elapsed;
    }
    if (elapsed < mRequest.GetMaxLookupTime())
    {
        return mRequest.GetMaxLookupTime() - elapsed;
    }

    ChipLogError(Discovery, "Unexpected timeout: lookup should have been cleaned already.");
    return System::Clock::Timeout::zero();
}

NodeLookupAction NodeLookupHandle::NextAction(System::Clock::Timestamp now)
{
    const System::Clock::Timestamp elapsed = now - mRequestStartTime;

    ChipLogProgress(Discovery, "Checking node lookup status after %lu ms", static_cast<unsigned long>(elapsed.count()));

    // We are still within the minimal search time. Wait for more results.
    if (elapsed < mRequest.GetMinLookupTime())
    {
        ChipLogProgress(Discovery, "Keeping DNSSD lookup active");
        return NodeLookupAction::KeepSearching();
    }

    // Minimal time to search reached. If any IP available, ready to return it.
    if (mBestAddressScore > ScoreValue(IpScore::kInvalid))
    {
        return NodeLookupAction::Success(mBestResult);
    }

    // Give up if the maximum search time has been reached
    if (elapsed >= mRequest.GetMaxLookupTime())
    {
        return NodeLookupAction::Error(CHIP_ERROR_TIMEOUT);
    }

    return NodeLookupAction::KeepSearching();
}

CHIP_ERROR Resolver::LookupNode(const NodeLookupRequest & request, Impl::NodeLookupHandle & handle)
{
    VerifyOrReturnError(mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE);

    handle.ResetForLookup(mTimeSource.GetMonotonicTimestamp(), request);
    ReturnErrorOnFailure(Dnssd::Resolver::Instance().ResolveNodeId(request.GetPeerId(), Inet::IPAddressType::kAny));
    mActiveLookups.PushBack(&handle);
    ReArmTimer();
    return CHIP_NO_ERROR;
}

CHIP_ERROR Resolver::CancelLookup(Impl::NodeLookupHandle & handle, FailureCallback cancel_method)
{
    VerifyOrReturnError(handle.IsActive(), CHIP_ERROR_INVALID_ARGUMENT);
    mActiveLookups.Remove(&handle);

    // Adjust any timing updates.
    ReArmTimer();

    if (cancel_method == FailureCallback::Call)
    {
        handle.GetListener()->OnNodeAddressResolutionFailed(handle.GetRequest().GetPeerId(), CHIP_ERROR_CANCELLED);
    }

    // TODO: There should be some form of cancel into Dnssd::Resolver::Instance()
    //       to stop any resolution mechanism if applicable.
    //
    // Current code just removes the internal list and any callbacks of resolution will
    // be ignored. This works from the perspective of the caller of this method,
    // but may be wasteful by letting dnssd still work in the background.

    return CHIP_NO_ERROR;
}

CHIP_ERROR Resolver::Init(System::Layer * systemLayer)
{
    mSystemLayer = systemLayer;
    Dnssd::Resolver::Instance().SetOperationalDelegate(this);
    return CHIP_NO_ERROR;
}

void Resolver::Shutdown()
{
    while (mActiveLookups.begin() != mActiveLookups.end())
    {
        auto current = mActiveLookups.begin();

        const PeerId peerId     = current->GetRequest().GetPeerId();
        NodeListener * listener = current->GetListener();

        mActiveLookups.Erase(current);

        // Failure callback only called after iterator was cleared:
        // This allows failure handlers to deallocate structures that may
        // contain the active lookup data as a member (intrusive lists members)
        listener->OnNodeAddressResolutionFailed(peerId, CHIP_ERROR_SHUT_DOWN);
    }

    // Re-arm of timer is expected to cancel any active timer as the
    // internal list of active lookups is empty at this point.
    ReArmTimer();

    mSystemLayer = nullptr;
    Dnssd::Resolver::Instance().SetOperationalDelegate(nullptr);
}

void Resolver::OnOperationalNodeResolved(const Dnssd::ResolvedNodeData & nodeData)
{
    auto it = mActiveLookups.begin();
    while (it != mActiveLookups.end())
    {
        auto current = it;
        it++;
        if (current->GetRequest().GetPeerId() != nodeData.operationalData.peerId)
        {
            continue;
        }

        ResolveResult result;

        result.address.SetPort(nodeData.resolutionData.port);
        result.address.SetInterface(nodeData.resolutionData.interfaceId);
        result.mrpRemoteConfig = nodeData.resolutionData.GetRemoteMRPConfig();
        result.supportsTcp     = nodeData.resolutionData.supportsTcp;

        for (size_t i = 0; i < nodeData.resolutionData.numIPs; i++)
        {
#if !INET_CONFIG_ENABLE_IPV4
            if (!nodeData.resolutionData.ipAddress[i].IsIPv6())
            {
                ChipLogError(Discovery, "Skipping IPv4 address during operational resolve.");
                continue;
            }
#endif
            result.address.SetIPAddress(nodeData.resolutionData.ipAddress[i]);
            current->LookupResult(result);
        }

        HandleAction(current);
    }

    ReArmTimer();
}

void Resolver::HandleAction(IntrusiveList<NodeLookupHandle>::Iterator & current)
{
    const NodeLookupAction action = current->NextAction(mTimeSource.GetMonotonicTimestamp());

    if (action.Type() == NodeLookupResult::kKeepSearching)
    {
        // No change in iterator
        return;
    }

    // final result, handle either success or failure
    const PeerId peerId     = current->GetRequest().GetPeerId();
    NodeListener * listener = current->GetListener();
    mActiveLookups.Erase(current);

    // ensure action is taken AFTER the current current lookup is marked complete
    // This allows failure handlers to deallocate structures that may
    // contain the active lookup data as a member (intrusive lists members)
    switch (action.Type())
    {
    case NodeLookupResult::kLookupError:
        listener->OnNodeAddressResolutionFailed(peerId, action.ErrorResult());
        break;
    case NodeLookupResult::kLookupSuccess:
        listener->OnNodeAddressResolved(peerId, action.ResolveResult());
        break;
    default:
        ChipLogError(Discovery, "Unexpected lookup state (not success or fail).");
        break;
    }
}

void Resolver::HandleTimer()
{
    auto it = mActiveLookups.begin();
    while (it != mActiveLookups.end())
    {
        auto current = it;
        it++;

        HandleAction(current);
    }

    ReArmTimer();
}

void Resolver::OnOperationalNodeResolutionFailed(const PeerId & peerId, CHIP_ERROR error)
{
    auto it = mActiveLookups.begin();
    while (it != mActiveLookups.end())
    {
        auto current = it;
        it++;
        if (current->GetRequest().GetPeerId() != peerId)
        {
            continue;
        }

        NodeListener * listener = current->GetListener();
        mActiveLookups.Erase(current);

        // Failure callback only called after iterator was cleared:
        // This allows failure handlers to deallocate structures that may
        // contain the active lookup data as a member (intrusive lists members)
        listener->OnNodeAddressResolutionFailed(peerId, error);
    }
    ReArmTimer();
}

void Resolver::ReArmTimer()
{
    mSystemLayer->CancelTimer(&OnResolveTimer, static_cast<void *>(this));

    System::Clock::Timestamp now = mTimeSource.GetMonotonicTimestamp();

    System::Clock::Timeout nextTimeout = kInvalidTimeout;
    for (auto it = mActiveLookups.begin(); it != mActiveLookups.end(); it++)
    {
        System::Clock::Timeout timeout = it->NextEventTimeout(now);

        if (timeout < nextTimeout)
        {
            nextTimeout = timeout;
        }
    }

    if (nextTimeout == kInvalidTimeout)
    {
#if CHIP_MINMDNS_HIGH_VERBOSITY
        // Generally this is only expected when no active lookups exist
        ChipLogProgress(Discovery, "Discovery does not require any more timeouts");
#endif
        return;
    }

    CHIP_ERROR err = mSystemLayer->StartTimer(nextTimeout, &OnResolveTimer, static_cast<void *>(this));
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(Discovery, "Timer schedule error %s assumed permanent", err.AsString());

        // Clear out all active lookups: without timers there is no guarantee of success
        auto it = mActiveLookups.begin();
        while (it != mActiveLookups.end())
        {
            const PeerId peerId     = it->GetRequest().GetPeerId();
            NodeListener * listener = it->GetListener();

            mActiveLookups.Erase(it);
            it = mActiveLookups.begin();

            // Callback only called after active lookup is cleared
            // This allows failure handlers to deallocate structures that may
            // contain the active lookup data as a member (intrusive lists members)
            listener->OnNodeAddressResolutionFailed(peerId, err);
        }
    }
}

} // namespace Impl

Resolver & Resolver::Instance()
{
    static Impl::Resolver gResolver;
    return gResolver;
}

} // namespace AddressResolve
} // namespace chip
<commit_msg>Changing link order (#23265)<commit_after>/*
 *
 *    Copyright (c) 2022 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <lib/address_resolve/AddressResolve_DefaultImpl.h>

namespace chip {
namespace AddressResolve {
namespace Impl {
namespace {

static constexpr System::Clock::Timeout kInvalidTimeout{ System::Clock::Timeout::max() };

// IP addess "suitability"
//   - Larger value means "more suitable"
//   - Enum ordered ascending for easier read. Note however that order of
//     checks MUST match in ScoreIpAddress below.
enum class IpScore : unsigned
{
    kInvalid = 0, // No address available

    // "Other" IPv6 include:
    //   - invalid addresses (have seen router bugs during interop testing)
    //   - embedded IPv4 (::/80)
    kOtherIpv6 = 1,
    kIpv4      = 2, // Not Matter SPEC, so low priority
#ifdef __APPLE__
    kUniqueLocal                   = 3, // ULA. Thread devices use this
    kGlobalUnicast                 = 4, // Maybe routable, not local subnet
    kUniqueLocalWithSharedPrefix   = 5, // Prefix seems to match a local interface
    kGlobalUnicastWithSharedPrefix = 6, // Prefix seems to match a local interface
    kLinkLocal                     = 7, // Valid only on an interface
#else
    kLinkLocal                     = 3, // Valid only on an interface
    kUniqueLocal                   = 4, // ULA. Thread devices use this
    kGlobalUnicast                 = 5, // Maybe routable, not local subnet
    kUniqueLocalWithSharedPrefix   = 6, // Prefix seems to match a local interface
    kGlobalUnicastWithSharedPrefix = 7, // Prefix seems to match a local interface
#endif // __APPLE__
};

constexpr unsigned ScoreValue(IpScore score)
{
    return static_cast<unsigned>(score);
}

/**
 * Gives a score for an IP address, generally related to "how good" the address
 * is and how likely it is for it to be reachable.
 */
IpScore ScoreIpAddress(const Inet::IPAddress & ip, Inet::InterfaceId interfaceId)
{
    if (ip.IsIPv6())
    {
#ifdef __APPLE__
        if (ip.IsIPv6LinkLocal())
        {
            return IpScore::kLinkLocal;
        }
#endif // __APPLE__

        if (interfaceId.MatchLocalIPv6Subnet(ip))
        {
            if (ip.IsIPv6GlobalUnicast())
            {
                return IpScore::kGlobalUnicastWithSharedPrefix;
            }
            if (ip.IsIPv6ULA())
            {
                return IpScore::kUniqueLocalWithSharedPrefix;
            }
        }
        if (ip.IsIPv6GlobalUnicast())
        {
            return IpScore::kGlobalUnicast;
        }

        if (ip.IsIPv6ULA())
        {
            return IpScore::kUniqueLocal;
        }

#ifndef __APPLE__
        if (ip.IsIPv6LinkLocal())
        {
            return IpScore::kLinkLocal;
        }
#endif // __APPLE__

        return IpScore::kOtherIpv6;
    }

    return IpScore::kIpv4;
}

} // namespace

void NodeLookupHandle::ResetForLookup(System::Clock::Timestamp now, const NodeLookupRequest & request)
{
    mRequestStartTime = now;
    mRequest          = request;
    mBestResult       = ResolveResult();
    mBestAddressScore = ScoreValue(IpScore::kInvalid);
}

void NodeLookupHandle::LookupResult(const ResolveResult & result)
{
#if CHIP_PROGRESS_LOGGING
    char addr_string[Transport::PeerAddress::kMaxToStringSize];
    result.address.ToString(addr_string);
#endif

    unsigned newScore = ScoreValue(ScoreIpAddress(result.address.GetIPAddress(), result.address.GetInterface()));
    if (newScore > mBestAddressScore)
    {
        mBestResult       = result;
        mBestAddressScore = newScore;

        if (!mBestResult.address.GetIPAddress().IsIPv6LinkLocal())
        {
            // Only use the DNS-SD resolution's InterfaceID for addresses that are IPv6 LLA.
            // For all other addresses, we should rely on the device's routing table to route messages sent.
            // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread,
            // mDNS advertisements are not usually received on the same interface the peer is reachable on.
            mBestResult.address.SetInterface(Inet::InterfaceId::Null());
            ChipLogDetail(Discovery, "Lookup clearing interface for non LL address");
        }

#if CHIP_PROGRESS_LOGGING
        ChipLogProgress(Discovery, "%s: new best score: %u", addr_string, mBestAddressScore);
    }
    else
    {
        ChipLogProgress(Discovery, "%s: score has not improved: %u", addr_string, newScore);
#endif
    }
}

System::Clock::Timeout NodeLookupHandle::NextEventTimeout(System::Clock::Timestamp now)
{
    const System::Clock::Timestamp elapsed = now - mRequestStartTime;

    if (elapsed < mRequest.GetMinLookupTime())
    {
        return mRequest.GetMinLookupTime() - elapsed;
    }
    if (elapsed < mRequest.GetMaxLookupTime())
    {
        return mRequest.GetMaxLookupTime() - elapsed;
    }

    ChipLogError(Discovery, "Unexpected timeout: lookup should have been cleaned already.");
    return System::Clock::Timeout::zero();
}

NodeLookupAction NodeLookupHandle::NextAction(System::Clock::Timestamp now)
{
    const System::Clock::Timestamp elapsed = now - mRequestStartTime;

    ChipLogProgress(Discovery, "Checking node lookup status after %lu ms", static_cast<unsigned long>(elapsed.count()));

    // We are still within the minimal search time. Wait for more results.
    if (elapsed < mRequest.GetMinLookupTime())
    {
        ChipLogProgress(Discovery, "Keeping DNSSD lookup active");
        return NodeLookupAction::KeepSearching();
    }

    // Minimal time to search reached. If any IP available, ready to return it.
    if (mBestAddressScore > ScoreValue(IpScore::kInvalid))
    {
        return NodeLookupAction::Success(mBestResult);
    }

    // Give up if the maximum search time has been reached
    if (elapsed >= mRequest.GetMaxLookupTime())
    {
        return NodeLookupAction::Error(CHIP_ERROR_TIMEOUT);
    }

    return NodeLookupAction::KeepSearching();
}

CHIP_ERROR Resolver::LookupNode(const NodeLookupRequest & request, Impl::NodeLookupHandle & handle)
{
    VerifyOrReturnError(mSystemLayer != nullptr, CHIP_ERROR_INCORRECT_STATE);

    handle.ResetForLookup(mTimeSource.GetMonotonicTimestamp(), request);
    ReturnErrorOnFailure(Dnssd::Resolver::Instance().ResolveNodeId(request.GetPeerId(), Inet::IPAddressType::kAny));
    mActiveLookups.PushBack(&handle);
    ReArmTimer();
    return CHIP_NO_ERROR;
}

CHIP_ERROR Resolver::CancelLookup(Impl::NodeLookupHandle & handle, FailureCallback cancel_method)
{
    VerifyOrReturnError(handle.IsActive(), CHIP_ERROR_INVALID_ARGUMENT);
    mActiveLookups.Remove(&handle);

    // Adjust any timing updates.
    ReArmTimer();

    if (cancel_method == FailureCallback::Call)
    {
        handle.GetListener()->OnNodeAddressResolutionFailed(handle.GetRequest().GetPeerId(), CHIP_ERROR_CANCELLED);
    }

    // TODO: There should be some form of cancel into Dnssd::Resolver::Instance()
    //       to stop any resolution mechanism if applicable.
    //
    // Current code just removes the internal list and any callbacks of resolution will
    // be ignored. This works from the perspective of the caller of this method,
    // but may be wasteful by letting dnssd still work in the background.

    return CHIP_NO_ERROR;
}

CHIP_ERROR Resolver::Init(System::Layer * systemLayer)
{
    mSystemLayer = systemLayer;
    Dnssd::Resolver::Instance().SetOperationalDelegate(this);
    return CHIP_NO_ERROR;
}

void Resolver::Shutdown()
{
    while (mActiveLookups.begin() != mActiveLookups.end())
    {
        auto current = mActiveLookups.begin();

        const PeerId peerId     = current->GetRequest().GetPeerId();
        NodeListener * listener = current->GetListener();

        mActiveLookups.Erase(current);

        // Failure callback only called after iterator was cleared:
        // This allows failure handlers to deallocate structures that may
        // contain the active lookup data as a member (intrusive lists members)
        listener->OnNodeAddressResolutionFailed(peerId, CHIP_ERROR_SHUT_DOWN);
    }

    // Re-arm of timer is expected to cancel any active timer as the
    // internal list of active lookups is empty at this point.
    ReArmTimer();

    mSystemLayer = nullptr;
    Dnssd::Resolver::Instance().SetOperationalDelegate(nullptr);
}

void Resolver::OnOperationalNodeResolved(const Dnssd::ResolvedNodeData & nodeData)
{
    auto it = mActiveLookups.begin();
    while (it != mActiveLookups.end())
    {
        auto current = it;
        it++;
        if (current->GetRequest().GetPeerId() != nodeData.operationalData.peerId)
        {
            continue;
        }

        ResolveResult result;

        result.address.SetPort(nodeData.resolutionData.port);
        result.address.SetInterface(nodeData.resolutionData.interfaceId);
        result.mrpRemoteConfig = nodeData.resolutionData.GetRemoteMRPConfig();
        result.supportsTcp     = nodeData.resolutionData.supportsTcp;

        for (size_t i = 0; i < nodeData.resolutionData.numIPs; i++)
        {
#if !INET_CONFIG_ENABLE_IPV4
            if (!nodeData.resolutionData.ipAddress[i].IsIPv6())
            {
                ChipLogError(Discovery, "Skipping IPv4 address during operational resolve.");
                continue;
            }
#endif
            result.address.SetIPAddress(nodeData.resolutionData.ipAddress[i]);
            current->LookupResult(result);
        }

        HandleAction(current);
    }

    ReArmTimer();
}

void Resolver::HandleAction(IntrusiveList<NodeLookupHandle>::Iterator & current)
{
    const NodeLookupAction action = current->NextAction(mTimeSource.GetMonotonicTimestamp());

    if (action.Type() == NodeLookupResult::kKeepSearching)
    {
        // No change in iterator
        return;
    }

    // final result, handle either success or failure
    const PeerId peerId     = current->GetRequest().GetPeerId();
    NodeListener * listener = current->GetListener();
    mActiveLookups.Erase(current);

    // ensure action is taken AFTER the current current lookup is marked complete
    // This allows failure handlers to deallocate structures that may
    // contain the active lookup data as a member (intrusive lists members)
    switch (action.Type())
    {
    case NodeLookupResult::kLookupError:
        listener->OnNodeAddressResolutionFailed(peerId, action.ErrorResult());
        break;
    case NodeLookupResult::kLookupSuccess:
        listener->OnNodeAddressResolved(peerId, action.ResolveResult());
        break;
    default:
        ChipLogError(Discovery, "Unexpected lookup state (not success or fail).");
        break;
    }
}

void Resolver::HandleTimer()
{
    auto it = mActiveLookups.begin();
    while (it != mActiveLookups.end())
    {
        auto current = it;
        it++;

        HandleAction(current);
    }

    ReArmTimer();
}

void Resolver::OnOperationalNodeResolutionFailed(const PeerId & peerId, CHIP_ERROR error)
{
    auto it = mActiveLookups.begin();
    while (it != mActiveLookups.end())
    {
        auto current = it;
        it++;
        if (current->GetRequest().GetPeerId() != peerId)
        {
            continue;
        }

        NodeListener * listener = current->GetListener();
        mActiveLookups.Erase(current);

        // Failure callback only called after iterator was cleared:
        // This allows failure handlers to deallocate structures that may
        // contain the active lookup data as a member (intrusive lists members)
        listener->OnNodeAddressResolutionFailed(peerId, error);
    }
    ReArmTimer();
}

void Resolver::ReArmTimer()
{
    mSystemLayer->CancelTimer(&OnResolveTimer, static_cast<void *>(this));

    System::Clock::Timestamp now = mTimeSource.GetMonotonicTimestamp();

    System::Clock::Timeout nextTimeout = kInvalidTimeout;
    for (auto it = mActiveLookups.begin(); it != mActiveLookups.end(); it++)
    {
        System::Clock::Timeout timeout = it->NextEventTimeout(now);

        if (timeout < nextTimeout)
        {
            nextTimeout = timeout;
        }
    }

    if (nextTimeout == kInvalidTimeout)
    {
#if CHIP_MINMDNS_HIGH_VERBOSITY
        // Generally this is only expected when no active lookups exist
        ChipLogProgress(Discovery, "Discovery does not require any more timeouts");
#endif
        return;
    }

    CHIP_ERROR err = mSystemLayer->StartTimer(nextTimeout, &OnResolveTimer, static_cast<void *>(this));
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(Discovery, "Timer schedule error %s assumed permanent", err.AsString());

        // Clear out all active lookups: without timers there is no guarantee of success
        auto it = mActiveLookups.begin();
        while (it != mActiveLookups.end())
        {
            const PeerId peerId     = it->GetRequest().GetPeerId();
            NodeListener * listener = it->GetListener();

            mActiveLookups.Erase(it);
            it = mActiveLookups.begin();

            // Callback only called after active lookup is cleared
            // This allows failure handlers to deallocate structures that may
            // contain the active lookup data as a member (intrusive lists members)
            listener->OnNodeAddressResolutionFailed(peerId, err);
        }
    }
}

} // namespace Impl

Resolver & Resolver::Instance()
{
    static Impl::Resolver gResolver;
    return gResolver;
}

} // namespace AddressResolve
} // namespace chip
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SonyArw1Decompressor.h"
#include "common/Common.h"                // for uint32_t, uint8_t, uint16_t
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "decompressors/HuffmanTable.h"   // for HuffmanTable
#include "io/BitPumpMSB.h"                // for BitPumpMSB
#include <cassert>                        // for assert

namespace rawspeed {

SonyArw1Decompressor::SonyArw1Decompressor(const RawImage& img) : mRaw(img) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  const uint32_t w = mRaw->dim.x;
  const uint32_t h = mRaw->dim.y;

  if (w == 0 || h == 0 || h % 2 != 0 || w > 4600 || h > 3072)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
}

inline int SonyArw1Decompressor::getDiff(BitPumpMSB* bs, uint32_t len) {
  if (len == 0)
    return 0;
  int diff = bs->getBitsNoFill(len);
  return HuffmanTable::extend(diff, len);
}

void SonyArw1Decompressor::decompress(const ByteStream& input) const {
  const uint32_t w = mRaw->dim.x;
  const uint32_t h = mRaw->dim.y;

  assert(w > 0);
  assert(h > 0);
  assert(h % 2 == 0);

  BitPumpMSB bits(input);
  uint8_t* data = mRaw->getData();
  auto* dest = reinterpret_cast<uint16_t*>(&data[0]);
  uint32_t pitch = mRaw->pitch / sizeof(uint16_t);
  int sum = 0;
  for (int64_t x = w - 1; x >= 0; x--) {
    for (uint32_t y = 0; y < h + 1; y += 2) {
      bits.fill(32);

      if (y == h)
        y = 1;

      uint32_t len = 4 - bits.getBitsNoFill(2);

      if (len == 3 && bits.getBitsNoFill(1))
        len = 0;

      if (len == 4)
        while (len < 17 && !bits.getBitsNoFill(1))
          len++;

      int diff = getDiff(&bits, len);
      sum += diff;

      if (sum < 0 || (sum >> 12) > 0)
        ThrowRDE("Error decompressing");

      if (y < h)
        dest[x + y * pitch] = sum;
    }
  }
}

} // namespace rawspeed
<commit_msg>SonyArw1Decompressor::decompress(): migrate to getU16DataAsUncroppedArray2DRef()<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SonyArw1Decompressor.h"
#include "common/Common.h"                // for uint32_t, uint8_t, uint16_t
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "decompressors/HuffmanTable.h"   // for HuffmanTable
#include "io/BitPumpMSB.h"                // for BitPumpMSB
#include <cassert>                        // for assert

namespace rawspeed {

SonyArw1Decompressor::SonyArw1Decompressor(const RawImage& img) : mRaw(img) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  const uint32_t w = mRaw->dim.x;
  const uint32_t h = mRaw->dim.y;

  if (w == 0 || h == 0 || h % 2 != 0 || w > 4600 || h > 3072)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
}

inline int SonyArw1Decompressor::getDiff(BitPumpMSB* bs, uint32_t len) {
  if (len == 0)
    return 0;
  int diff = bs->getBitsNoFill(len);
  return HuffmanTable::extend(diff, len);
}

void SonyArw1Decompressor::decompress(const ByteStream& input) const {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
  assert(out.width > 0);
  assert(out.height > 0);
  assert(out.height % 2 == 0);

  BitPumpMSB bits(input);
  int pred = 0;
  for (int col = out.width - 1; col >= 0; col--) {
    for (int row = 0; row < out.height + 1; row += 2) {
      bits.fill(32);

      if (row == out.height)
        row = 1;

      uint32_t len = 4 - bits.getBitsNoFill(2);

      if (len == 3 && bits.getBitsNoFill(1))
        len = 0;

      if (len == 4)
        while (len < 17 && !bits.getBitsNoFill(1))
          len++;

      int diff = getDiff(&bits, len);
      pred += diff;

      if (pred < 0 || (pred >> 12) > 0)
        ThrowRDE("Error decompressing");

      if (row < out.height)
        out(row, col) = pred;
    }
  }
}

} // namespace rawspeed
<|endoftext|>


<commit_before>/** \file   Archive.cc
 *  \brief  Implementations of the archive processing functions and classes.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016-2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "Archive.h"
#include <cstring>
#include <fcntl.h>
#include "Compiler.h"
#include "File.h"
#include "FileUtil.h"
#include "StringUtil.h"
#include "util.h"

namespace Archive {

const std::string Reader::EntryInfo::getFilename() const {
    return ::archive_entry_pathname(archive_entry_);
}

bool Reader::EntryInfo::isRegularFile() const {
    return ::archive_entry_filetype(archive_entry_) == AE_IFREG;
}

bool Reader::EntryInfo::isDirectory() const {
    return ::archive_entry_filetype(archive_entry_) == AE_IFDIR;
}

const unsigned DEFAULT_BLOCKSIZE(10240);

Reader::Reader(const std::string &archive_file_name) {
    archive_handle_ = ::archive_read_new();
    ::archive_read_support_filter_all(archive_handle_);
    ::archive_read_support_format_all(archive_handle_);
    if (unlikely(::archive_read_open_filename(archive_handle_, archive_file_name.c_str(), DEFAULT_BLOCKSIZE)
                 != ARCHIVE_OK))
        LOG_ERROR("archive_read_open_filename(3) failed: " + std::string(::archive_error_string(archive_handle_)));
}

Reader::~Reader() {
    if (unlikely(::archive_read_free(archive_handle_) != ARCHIVE_OK))
        LOG_ERROR("archive_read_free(3) failed!");
}

bool Reader::getNext(EntryInfo * const info) {
    int status;
    while ((status = ::archive_read_next_header(archive_handle_, &info->archive_entry_)) == ARCHIVE_RETRY)
        /* Intentionally empty! */;

    if (status == ARCHIVE_OK)
        return true;
    if (status == ARCHIVE_EOF)
        return false;

    LOG_ERROR("something went wrong! (" + std::string(::archive_error_string(archive_handle_)) + ")");
}

ssize_t Reader::read(char * const buffer, const size_t size) {
    ssize_t retval;
    do
        retval = ::archive_read_data(archive_handle_, reinterpret_cast<void *>(buffer), size);
    while (retval == ARCHIVE_RETRY);

    return (retval == ARCHIVE_FATAL or retval == ARCHIVE_WARN) ? -1 : retval;
}

bool Reader::extractEntry(const std::string &member_name, std::string output_filename) {
    if (output_filename.empty())
        output_filename = member_name;

    EntryInfo entry_info;
    while (getNext(&entry_info)) {
        if (entry_info.getFilename() != member_name)
            continue;

        if (entry_info.isDirectory())
            LOG_ERROR("an't extract a directory!");

        const int to_fd(::open(output_filename.c_str(), O_WRONLY | O_CREAT, 0600));
        if (unlikely(to_fd == -1))
            LOG_ERROR("failed to open \"" + output_filename  + "\" for writing!");

        char buf[BUFSIZ];
        for (;;) {
            const ssize_t no_of_bytes(read(&buf[0], sizeof(buf)));
            if (no_of_bytes == 0) {
                ::close(to_fd);
                return true;
            }

            if (unlikely(no_of_bytes < 0))
                LOG_ERROR(getLastErrorMessage());

            if (unlikely(::write(to_fd, &buf[0], no_of_bytes) != no_of_bytes))
                LOG_ERROR("write(2) failed!");
        }

        ::close(to_fd);
    }

    return false;
}

Writer::Writer(const std::string &archive_file_name, const std::string &archive_write_options, const FileType file_type)
    : archive_entry_(nullptr), closed_(false)
{
    archive_handle_ = ::archive_write_new();

    switch (file_type) {
    case FileType::AUTO:
        if (StringUtil::EndsWith(archive_file_name, ".tar")) {
            if (unlikely(not archive_write_options.empty()))
                LOG_ERROR("no write options are currently supported for the uncompressed tar format!");
            ::archive_write_set_format_pax_restricted(archive_handle_);
        } else if (StringUtil::EndsWith(archive_file_name, ".tar.gz")) {
            ::archive_write_add_filter_gzip(archive_handle_);
            if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
                LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"!");
            ::archive_write_set_format_pax_restricted(archive_handle_);
        } else if (StringUtil::EndsWith(archive_file_name, ".zip")) {
            ::archive_write_set_format_zip(archive_handle_);
            if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
                LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"!");
        } else
            LOG_ERROR("FileType::AUTO selected but," " can't guess the file type from the given filename \"" + archive_file_name + "\"!");
        break;
    case FileType::TAR:
        if (unlikely(not archive_write_options.empty()))
            LOG_ERROR("no write options are currently supported for the uncompressed tar format! (2)");
        ::archive_write_set_format_pax_restricted(archive_handle_);
        break;
    case FileType::GZIPPED_TAR:
        ::archive_write_add_filter_gzip(archive_handle_);
        if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
            LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"! (2)");
        ::archive_write_set_format_pax_restricted(archive_handle_);
        break;
    case FileType::ZIP:
        ::archive_write_set_format_zip(archive_handle_);
        if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
            LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"! (3)");
        break;
    }

    if (unlikely(::archive_write_open_filename(archive_handle_, archive_file_name.c_str()) != ARCHIVE_OK))
        LOG_ERROR("archive_write_open_filename(3) failed: " + std::string(::archive_error_string(archive_handle_)));
}

void Writer::close() {
    if (closed_)
        return;

    if (archive_entry_ != nullptr)
        ::archive_entry_free(archive_entry_);

    if (unlikely(::archive_write_close(archive_handle_) != ARCHIVE_OK))
        LOG_ERROR("archive_write_close(3) failed: " + std::string(::archive_error_string(archive_handle_)));
    if (unlikely(::archive_write_free(archive_handle_) != ARCHIVE_OK))
        LOG_ERROR("archive_write_free(3) failed: " + std::string(::archive_error_string(archive_handle_)));

    closed_ = true;
}

void Writer::add(const std::string &filename, std::string archive_name) {
    if (archive_name.empty())
        archive_name = filename;
    if (unlikely(already_seen_archive_names_.find(archive_name) != already_seen_archive_names_.end()))
        LOG_ERROR("attempt to store a duplicate archive entry name \"" + archive_name + "\"!");
    else
        already_seen_archive_names_.emplace(archive_name);

    struct stat stat_buf;
    if (unlikely(::stat(filename.c_str(), &stat_buf) != 0))
        LOG_ERROR("stat(2) on \"" + filename + "\" failed: " + std::string(::strerror(errno)));

    if (archive_entry_ == nullptr)
        archive_entry_ = ::archive_entry_new();
    else
        ::archive_entry_clear(archive_entry_);
    ::archive_entry_set_pathname(archive_entry_, archive_name.c_str());
    ::archive_entry_copy_stat(archive_entry_, &stat_buf);

    int status;
    while ((status = ::archive_write_header(archive_handle_, archive_entry_)) == ARCHIVE_RETRY)
        /* Intentionally empty! */;
    if (unlikely(status != ARCHIVE_OK))
        LOG_ERROR("archive_write_header(3) failed! (" + std::string(::archive_error_string(archive_handle_)));

    File input(filename, "r", File::THROW_ON_ERROR);
    char buffer[DEFAULT_BLOCKSIZE];
    size_t count;
    while ((count = input.read(buffer, DEFAULT_BLOCKSIZE)) > 0) {
        if (count < DEFAULT_BLOCKSIZE and input.anErrorOccurred())
            LOG_ERROR("error reading \"" + filename + "\" !");
        write(buffer, count);
    }
}

void Writer::addEntry(const std::string &filename, const int64_t size, const mode_t mode, const EntryType entry_type) {
    if (archive_entry_ != nullptr)
        ::archive_entry_clear(archive_entry_);
    else
        archive_entry_ = ::archive_entry_new();

    ::archive_entry_set_pathname(archive_entry_, filename.c_str());
    ::archive_entry_set_size(archive_entry_, size);
    if (entry_type == EntryType::REGULAR_FILE)
        ::archive_entry_set_filetype(archive_entry_, AE_IFREG);
    else
        LOG_ERROR("unsupported entry type: " + std::to_string(static_cast<int>(entry_type)) + "!");
    ::archive_entry_set_perm(archive_entry_, mode);
    ::archive_write_header(archive_handle_, archive_entry_);
}

void Writer::write(const char * const buffer, const size_t size) {
    if (unlikely(::archive_write_data(archive_handle_, buffer, size) != static_cast<ssize_t>(size)))
        LOG_ERROR("archive_write_data(3) failed: " + std::string(::archive_error_string(archive_handle_)));
}

void UnpackArchive(const std::string &archive_name, const std::string &directory) {
    if (unlikely(not FileUtil::MakeDirectory(directory)))
        LOG_ERROR("failed to create directory \"" + directory + "\"!");

    Reader reader(archive_name);
    Reader::EntryInfo file_info;
    while (reader.getNext(&file_info)) {
        if (file_info.empty())
            continue;

        if (unlikely(not file_info.isRegularFile()))
            LOG_ERROR("unexpectedly, the entry \"" + file_info.getFilename() + "\" in \"" + archive_name + "\" is not a regular file!");

        const std::string output_filename(directory + "/" + file_info.getFilename());
        const auto output(FileUtil::OpenOutputFileOrDie(output_filename));

        char buf[8192];
        size_t read_count;
        while ((read_count = reader.read(buf, sizeof buf)) > 0) {
            if (unlikely(output->write(buf, read_count) != read_count))
                LOG_ERROR("failed to write data to \"" + output->getPath() + "\"! (No room?)");
        }
    }

}

} // namespace Archive
<commit_msg>Checked more return codes.<commit_after>/** \file   Archive.cc
 *  \brief  Implementations of the archive processing functions and classes.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016-2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "Archive.h"
#include <cstring>
#include <fcntl.h>
#include "Compiler.h"
#include "File.h"
#include "FileUtil.h"
#include "StringUtil.h"
#include "util.h"

namespace Archive {

const std::string Reader::EntryInfo::getFilename() const {
    return ::archive_entry_pathname(archive_entry_);
}

bool Reader::EntryInfo::isRegularFile() const {
    return ::archive_entry_filetype(archive_entry_) == AE_IFREG;
}

bool Reader::EntryInfo::isDirectory() const {
    return ::archive_entry_filetype(archive_entry_) == AE_IFDIR;
}

const unsigned DEFAULT_BLOCKSIZE(10240);

Reader::Reader(const std::string &archive_file_name) {
    archive_handle_ = ::archive_read_new();
    ::archive_read_support_filter_all(archive_handle_);
    ::archive_read_support_format_all(archive_handle_);
    if (unlikely(::archive_read_open_filename(archive_handle_, archive_file_name.c_str(), DEFAULT_BLOCKSIZE)
                 != ARCHIVE_OK))
        LOG_ERROR("archive_read_open_filename(3) failed: " + std::string(::archive_error_string(archive_handle_)));
}

Reader::~Reader() {
    if (unlikely(::archive_read_free(archive_handle_) != ARCHIVE_OK))
        LOG_ERROR("archive_read_free(3) failed!");
}

bool Reader::getNext(EntryInfo * const info) {
    int status;
    while ((status = ::archive_read_next_header(archive_handle_, &info->archive_entry_)) == ARCHIVE_RETRY)
        /* Intentionally empty! */;

    if (status == ARCHIVE_OK)
        return true;
    if (status == ARCHIVE_EOF)
        return false;

    LOG_ERROR("something went wrong! (" + std::string(::archive_error_string(archive_handle_)) + ")");
}

ssize_t Reader::read(char * const buffer, const size_t size) {
    ssize_t retval;
    do
        retval = ::archive_read_data(archive_handle_, reinterpret_cast<void *>(buffer), size);
    while (retval == ARCHIVE_RETRY);

    return (retval == ARCHIVE_FATAL or retval == ARCHIVE_WARN) ? -1 : retval;
}

bool Reader::extractEntry(const std::string &member_name, std::string output_filename) {
    if (output_filename.empty())
        output_filename = member_name;

    EntryInfo entry_info;
    while (getNext(&entry_info)) {
        if (entry_info.getFilename() != member_name)
            continue;

        if (entry_info.isDirectory())
            LOG_ERROR("an't extract a directory!");

        const int to_fd(::open(output_filename.c_str(), O_WRONLY | O_CREAT, 0600));
        if (unlikely(to_fd == -1))
            LOG_ERROR("failed to open \"" + output_filename  + "\" for writing!");

        char buf[BUFSIZ];
        for (;;) {
            const ssize_t no_of_bytes(read(&buf[0], sizeof(buf)));
            if (no_of_bytes == 0) {
                ::close(to_fd);
                return true;
            }

            if (unlikely(no_of_bytes < 0))
                LOG_ERROR(getLastErrorMessage());

            if (unlikely(::write(to_fd, &buf[0], no_of_bytes) != no_of_bytes))
                LOG_ERROR("write(2) failed!");
        }

        ::close(to_fd);
    }

    return false;
}

Writer::Writer(const std::string &archive_file_name, const std::string &archive_write_options, const FileType file_type)
    : archive_entry_(nullptr), closed_(false)
{
    archive_handle_ = ::archive_write_new();

    switch (file_type) {
    case FileType::AUTO:
        if (StringUtil::EndsWith(archive_file_name, ".tar")) {
            if (unlikely(not archive_write_options.empty()))
                LOG_ERROR("no write options are currently supported for the uncompressed tar format!");
            if (::archive_write_set_format_pax_restricted(archive_handle_) != ARCHIVE_OK)
                LOG_ERROR("failed to call archive_write_set_format_pax_restricted(3): " + std::string(::archive_error_string(archive_handle_)));
        } else if (StringUtil::EndsWith(archive_file_name, ".tar.gz")) {
            if (::archive_write_add_filter_gzip(archive_handle_) != ARCHIVE_OK)
                LOG_ERROR("failed to call archive_write_add_filter_gzip(3): " + std::string(::archive_error_string(archive_handle_)));
            if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
                LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"!");
            if (::archive_write_set_format_pax_restricted(archive_handle_) != ARCHIVE_OK)
                LOG_ERROR("failed to call archive_write_set_format_pax_restricted(3): " + std::string(::archive_error_string(archive_handle_)));
        } else if (StringUtil::EndsWith(archive_file_name, ".zip")) {
            if (::archive_write_set_format_zip(archive_handle_) != ARCHIVE_OK)
                LOG_ERROR("failed to call archive_write_set_format_zip(3): " + std::string(::archive_error_string(archive_handle_)));
            if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
                LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"!");
        } else
            LOG_ERROR("FileType::AUTO selected but," " can't guess the file type from the given filename \"" + archive_file_name + "\"!");
        break;
    case FileType::TAR:
        if (unlikely(not archive_write_options.empty()))
            LOG_ERROR("no write options are currently supported for the uncompressed tar format! (2)");
        if (::archive_write_set_format_pax_restricted(archive_handle_) != ARCHIVE_OK)
            LOG_ERROR("failed to call archive_write_set_format_pax_restricted(3): " + std::string(::archive_error_string(archive_handle_)));
        break;
    case FileType::GZIPPED_TAR:
        if (::archive_write_add_filter_gzip(archive_handle_) != ARCHIVE_OK)
            LOG_ERROR("failed to call archive_write_add_filter_gzip(3): " + std::string(::archive_error_string(archive_handle_)));
        if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
            LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"! (2)");
        if (::archive_write_set_format_pax_restricted(archive_handle_) != ARCHIVE_OK)
            LOG_ERROR("failed to call archive_write_set_format_pax_restricted(3): " + std::string(::archive_error_string(archive_handle_)));
        break;
    case FileType::ZIP:
        if (::archive_write_set_format_zip(archive_handle_) != ARCHIVE_OK)
            LOG_ERROR("failed to call archive_write_set_format_zip(3): " + std::string(::archive_error_string(archive_handle_)));
        if (unlikely(::archive_write_set_options(archive_handle_, archive_write_options.c_str()) != ARCHIVE_OK))
            LOG_ERROR("failed to call archive_write_set_options(3) w/ \"" + archive_write_options + "\"! (3)");
        break;
    }

    if (unlikely(::archive_write_open_filename(archive_handle_, archive_file_name.c_str()) != ARCHIVE_OK))
        LOG_ERROR("archive_write_open_filename(3) failed: " + std::string(::archive_error_string(archive_handle_)));
}

void Writer::close() {
    if (closed_)
        return;

    if (archive_entry_ != nullptr)
        ::archive_entry_free(archive_entry_);

    if (unlikely(::archive_write_close(archive_handle_) != ARCHIVE_OK))
        LOG_ERROR("archive_write_close(3) failed: " + std::string(::archive_error_string(archive_handle_)));
    if (unlikely(::archive_write_free(archive_handle_) != ARCHIVE_OK))
        LOG_ERROR("archive_write_free(3) failed: " + std::string(::archive_error_string(archive_handle_)));

    closed_ = true;
}

void Writer::add(const std::string &filename, std::string archive_name) {
    if (archive_name.empty())
        archive_name = filename;
    if (unlikely(already_seen_archive_names_.find(archive_name) != already_seen_archive_names_.end()))
        LOG_ERROR("attempt to store a duplicate archive entry name \"" + archive_name + "\"!");
    else
        already_seen_archive_names_.emplace(archive_name);

    struct stat stat_buf;
    if (unlikely(::stat(filename.c_str(), &stat_buf) != 0))
        LOG_ERROR("stat(2) on \"" + filename + "\" failed: " + std::string(::strerror(errno)));

    if (archive_entry_ == nullptr)
        archive_entry_ = ::archive_entry_new();
    else
        ::archive_entry_clear(archive_entry_);
    ::archive_entry_set_pathname(archive_entry_, archive_name.c_str());
    ::archive_entry_copy_stat(archive_entry_, &stat_buf);

    int status;
    while ((status = ::archive_write_header(archive_handle_, archive_entry_)) == ARCHIVE_RETRY)
        /* Intentionally empty! */;
    if (unlikely(status != ARCHIVE_OK))
        LOG_ERROR("archive_write_header(3) failed! (" + std::string(::archive_error_string(archive_handle_)));

    File input(filename, "r", File::THROW_ON_ERROR);
    char buffer[DEFAULT_BLOCKSIZE];
    size_t count;
    while ((count = input.read(buffer, DEFAULT_BLOCKSIZE)) > 0) {
        if (count < DEFAULT_BLOCKSIZE and input.anErrorOccurred())
            LOG_ERROR("error reading \"" + filename + "\" !");
        write(buffer, count);
    }
}

void Writer::addEntry(const std::string &filename, const int64_t size, const mode_t mode, const EntryType entry_type) {
    if (archive_entry_ != nullptr)
        ::archive_entry_clear(archive_entry_);
    else
        archive_entry_ = ::archive_entry_new();

    ::archive_entry_set_pathname(archive_entry_, filename.c_str());
    ::archive_entry_set_size(archive_entry_, size);
    if (entry_type == EntryType::REGULAR_FILE)
        ::archive_entry_set_filetype(archive_entry_, AE_IFREG);
    else
        LOG_ERROR("unsupported entry type: " + std::to_string(static_cast<int>(entry_type)) + "!");
    ::archive_entry_set_perm(archive_entry_, mode);
    ::archive_write_header(archive_handle_, archive_entry_);
}

void Writer::write(const char * const buffer, const size_t size) {
    if (unlikely(::archive_write_data(archive_handle_, buffer, size) != static_cast<ssize_t>(size)))
        LOG_ERROR("archive_write_data(3) failed: " + std::string(::archive_error_string(archive_handle_)));
}

void UnpackArchive(const std::string &archive_name, const std::string &directory) {
    if (unlikely(not FileUtil::MakeDirectory(directory)))
        LOG_ERROR("failed to create directory \"" + directory + "\"!");

    Reader reader(archive_name);
    Reader::EntryInfo file_info;
    while (reader.getNext(&file_info)) {
        if (file_info.empty())
            continue;

        if (unlikely(not file_info.isRegularFile()))
            LOG_ERROR("unexpectedly, the entry \"" + file_info.getFilename() + "\" in \"" + archive_name + "\" is not a regular file!");

        const std::string output_filename(directory + "/" + file_info.getFilename());
        const auto output(FileUtil::OpenOutputFileOrDie(output_filename));

        char buf[8192];
        size_t read_count;
        while ((read_count = reader.read(buf, sizeof buf)) > 0) {
            if (unlikely(output->write(buf, read_count) != read_count))
                LOG_ERROR("failed to write data to \"" + output->getPath() + "\"! (No room?)");
        }
    }

}

} // namespace Archive
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5previewnodeinstanceserver.h"

#include "nodeinstanceclientinterface.h"
#include "statepreviewimagechangedcommand.h"
#include "createscenecommand.h"
#include "removesharedmemorycommand.h"
#include <QQuickView>
#include <QQuickItem>
#include <designersupport.h>

namespace QmlDesigner {

Qt5PreviewNodeInstanceServer::Qt5PreviewNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
}

void Qt5PreviewNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    initializeView(command.imports());
    setupScene(command);

    startRenderTimer();
}
void Qt5PreviewNodeInstanceServer::startRenderTimer()
{
    if (timerId() != 0)
        killTimer(timerId());

    int timerId = startTimer(renderTimerInterval());

    setTimerId(timerId);
}

void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;

    if (!rootNodeInstance().holdsGraphical())
        return;

    if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) {
        inFunction = true;

        DesignerSupport::polishItems(quickView());

        QVector<ImageContainer> imageContainerVector;
        imageContainerVector.append(ImageContainer(0, renderPreviewImage(), -1));

        foreach (ServerNodeInstance instance,  rootNodeInstance().stateInstances()) {
            instance.activateState();
            QImage previewImage = renderPreviewImage();
            if (!previewImage.isNull())
                imageContainerVector.append(ImageContainer(instance.instanceId(), renderPreviewImage(), instance.instanceId()));
            instance.deactivateState();
        }

        nodeInstanceClient()->statePreviewImagesChanged(StatePreviewImageChangedCommand(imageContainerVector));

        slowDownRenderTimer();
        inFunction = false;
    }
}

void Qt5PreviewNodeInstanceServer::changeState(const ChangeStateCommand &/*command*/)
{

}

QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
{
    rootNodeInstance().updateDirtyNodeRecursive();

    QRectF boundingRect = rootNodeInstance().boundingRect();

    QSize previewImageSize = boundingRect.size().toSize();
    previewImageSize.scale(QSize(100, 100), Qt::KeepAspectRatio);

    QImage previewImage = rootNodeInstance().renderPreviewImage(previewImageSize);

    return previewImage;
}

void QmlDesigner::Qt5PreviewNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command)
{
    if (command.typeName() == "Image")
        ImageContainer::removeSharedMemorys(command.keyNumbers());
}

} // namespace QmlDesigner
<commit_msg>QmlDesigner: Slow down the preview timer<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5previewnodeinstanceserver.h"

#include "nodeinstanceclientinterface.h"
#include "statepreviewimagechangedcommand.h"
#include "createscenecommand.h"
#include "removesharedmemorycommand.h"
#include <QQuickView>
#include <QQuickItem>
#include <designersupport.h>

namespace QmlDesigner {

Qt5PreviewNodeInstanceServer::Qt5PreviewNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
    setSlowRenderTimerInterval(100000000);
    setRenderTimerInterval(100);
}

void Qt5PreviewNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    initializeView(command.imports());
    setupScene(command);

    startRenderTimer();
}
void Qt5PreviewNodeInstanceServer::startRenderTimer()
{
    if (timerId() != 0)
        killTimer(timerId());

    int timerId = startTimer(renderTimerInterval());

    setTimerId(timerId);
}

void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;

    if (!rootNodeInstance().holdsGraphical())
        return;

    if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) {
        inFunction = true;

        DesignerSupport::polishItems(quickView());

        QVector<ImageContainer> imageContainerVector;
        imageContainerVector.append(ImageContainer(0, renderPreviewImage(), -1));

        foreach (ServerNodeInstance instance,  rootNodeInstance().stateInstances()) {
            instance.activateState();
            QImage previewImage = renderPreviewImage();
            if (!previewImage.isNull())
                imageContainerVector.append(ImageContainer(instance.instanceId(), renderPreviewImage(), instance.instanceId()));
            instance.deactivateState();
        }

        nodeInstanceClient()->statePreviewImagesChanged(StatePreviewImageChangedCommand(imageContainerVector));

        slowDownRenderTimer();
        inFunction = false;
    }
}

void Qt5PreviewNodeInstanceServer::changeState(const ChangeStateCommand &/*command*/)
{

}

QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
{
    rootNodeInstance().updateDirtyNodeRecursive();

    QRectF boundingRect = rootNodeInstance().boundingRect();

    QSize previewImageSize = boundingRect.size().toSize();
    previewImageSize.scale(QSize(100, 100), Qt::KeepAspectRatio);

    QImage previewImage = rootNodeInstance().renderPreviewImage(previewImageSize);

    return previewImage;
}

void QmlDesigner::Qt5PreviewNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command)
{
    if (command.typeName() == "Image")
        ImageContainer::removeSharedMemorys(command.keyNumbers());
}

} // namespace QmlDesigner
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5previewnodeinstanceserver.h"

#include "nodeinstanceclientinterface.h"
#include "statepreviewimagechangedcommand.h"
#include "createscenecommand.h"
#include "removesharedmemorycommand.h"
#include <QQuickView>
#include <QQuickItem>
#include <designersupport.h>

namespace QmlDesigner {

Qt5PreviewNodeInstanceServer::Qt5PreviewNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
}

void Qt5PreviewNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    initializeView(command.imports());
    setupScene(command);

    startRenderTimer();
}
void Qt5PreviewNodeInstanceServer::startRenderTimer()
{
    if (timerId() != 0)
        killTimer(timerId());

    int timerId = startTimer(renderTimerInterval());

    setTimerId(timerId);
}

void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;

    if (rootNodeInstance().internalSGItem() == 0)
        return;

    if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) {
        inFunction = true;
        QVector<ImageContainer> imageContainerVector;
        imageContainerVector.append(ImageContainer(0, renderPreviewImage(), -1));

        foreach (ServerNodeInstance instance,  rootNodeInstance().stateInstances()) {
            instance.activateState();
            imageContainerVector.append(ImageContainer(instance.instanceId(), renderPreviewImage(), instance.instanceId()));
            instance.deactivateState();
        }

        nodeInstanceClient()->statePreviewImagesChanged(StatePreviewImageChangedCommand(imageContainerVector));

        slowDownRenderTimer();
        inFunction = false;
    }
}

void Qt5PreviewNodeInstanceServer::changeState(const ChangeStateCommand &/*command*/)
{

}

static void updateDirtyNodeRecursive(QQuickItem *parentItem)
{
    foreach (QQuickItem *childItem, parentItem->childItems())
        updateDirtyNodeRecursive(childItem);

    DesignerSupport::updateDirtyNode(parentItem);
}

QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
{
    updateDirtyNodeRecursive(rootNodeInstance().internalSGItem());

    QRectF boundingRect = rootNodeInstance().boundingRect();

    QSize previewImageSize = boundingRect.size().toSize();
    previewImageSize.scale(QSize(100, 100), Qt::KeepAspectRatio);

    QImage previewImage;

    if (boundingRect.isValid() && rootNodeInstance().internalSGItem())
        previewImage = designerSupport()->renderImageForItem(rootNodeInstance().internalSGItem(), boundingRect, previewImageSize);

    previewImage = previewImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);

    return previewImage;
}

void QmlDesigner::Qt5PreviewNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command)
{
    if (command.typeName() == "Image")
        ImageContainer::removeSharedMemorys(command.keyNumbers());
}

} // namespace QmlDesigner
<commit_msg>QmlDesigner.NodeInstances: Don't send empty image for preview<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5previewnodeinstanceserver.h"

#include "nodeinstanceclientinterface.h"
#include "statepreviewimagechangedcommand.h"
#include "createscenecommand.h"
#include "removesharedmemorycommand.h"
#include <QQuickView>
#include <QQuickItem>
#include <designersupport.h>

namespace QmlDesigner {

Qt5PreviewNodeInstanceServer::Qt5PreviewNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
}

void Qt5PreviewNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    initializeView(command.imports());
    setupScene(command);

    startRenderTimer();
}
void Qt5PreviewNodeInstanceServer::startRenderTimer()
{
    if (timerId() != 0)
        killTimer(timerId());

    int timerId = startTimer(renderTimerInterval());

    setTimerId(timerId);
}

void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;

    if (rootNodeInstance().internalSGItem() == 0)
        return;

    if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) {
        inFunction = true;
        QVector<ImageContainer> imageContainerVector;
        imageContainerVector.append(ImageContainer(0, renderPreviewImage(), -1));

        foreach (ServerNodeInstance instance,  rootNodeInstance().stateInstances()) {
            instance.activateState();
            QImage previewImage = renderPreviewImage();
            if (!previewImage.isNull())
                imageContainerVector.append(ImageContainer(instance.instanceId(), renderPreviewImage(), instance.instanceId()));
            instance.deactivateState();
        }

        nodeInstanceClient()->statePreviewImagesChanged(StatePreviewImageChangedCommand(imageContainerVector));

        slowDownRenderTimer();
        inFunction = false;
    }
}

void Qt5PreviewNodeInstanceServer::changeState(const ChangeStateCommand &/*command*/)
{

}

static void updateDirtyNodeRecursive(QQuickItem *parentItem)
{
    foreach (QQuickItem *childItem, parentItem->childItems())
        updateDirtyNodeRecursive(childItem);

    DesignerSupport::updateDirtyNode(parentItem);
}

QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
{
    updateDirtyNodeRecursive(rootNodeInstance().internalSGItem());

    QRectF boundingRect = rootNodeInstance().boundingRect();

    QSize previewImageSize = boundingRect.size().toSize();
    previewImageSize.scale(QSize(100, 100), Qt::KeepAspectRatio);

    QImage previewImage;

    if (boundingRect.isValid() && rootNodeInstance().internalSGItem())
        previewImage = designerSupport()->renderImageForItem(rootNodeInstance().internalSGItem(), boundingRect, previewImageSize);

    previewImage = previewImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);

    return previewImage;
}

void QmlDesigner::Qt5PreviewNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command)
{
    if (command.typeName() == "Image")
        ImageContainer::removeSharedMemorys(command.keyNumbers());
}

} // namespace QmlDesigner
<|endoftext|>