<commit_before>/*************************************************************************
 *
 *  $RCSfile: service1_impl.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 00:09:50 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  the BSD license.
 *
 *  Copyright (c) 2003 by Sun Microsystems, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *************************************************************************/

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

#include <osl/interlck.h>
#include <osl/mutex.hxx>
#include <rtl/uuid.h>
#include <cppuhelper/factory.hxx>

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <my_module/XSomething.hpp>

using namespace ::rtl; // for OUString
using namespace ::com::sun::star; // for odk interfaces
using namespace ::com::sun::star::uno; // for basic types

namespace my_sc_impl
{

Sequence< OUString > SAL_CALL getSupportedServiceNames_MyService1Impl()
{
    Sequence< OUString > names(1);
    names[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("my_module.MyService1"));
    return names;
}

OUString SAL_CALL getImplementationName_MyService1Impl()
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
                         "my_module.my_sc_implementation.MyService1") );
}

class MyService1Impl
    : public ::my_module::XSomething
    , public lang::XServiceInfo
    , public lang::XTypeProvider
{
    oslInterlockedCount m_refcount;
    OUString m_sData;
    // it's good practise to store the context for further use when you use
    // other UNO API's in your implementation
    Reference< XComponentContext > m_xContext;
public:
    inline MyService1Impl(Reference< XComponentContext > const & xContext) throw ()
        : m_refcount( 0 ),
          m_xContext(xContext)
        {}

    virtual ~MyService1Impl() {}

    // XInterface
    virtual Any SAL_CALL queryInterface( Type const & type )
        throw (RuntimeException);
    virtual void SAL_CALL acquire()
        throw ();
    virtual void SAL_CALL release()
        throw ();
    // XTypeProvider
    virtual Sequence< Type > SAL_CALL getTypes()
        throw (RuntimeException);
    virtual Sequence< sal_Int8 > SAL_CALL getImplementationId()
        throw (RuntimeException);
    // XSomething
    virtual OUString SAL_CALL methodOne( OUString const & str )
        throw (RuntimeException);
    virtual OUString SAL_CALL methodTwo( )
        throw (RuntimeException);
    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName()
        throw (RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName )
        throw (RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
        throw (RuntimeException);
};

// XInterface implementation
Any MyService1Impl::queryInterface( Type const & type )
    throw (RuntimeException)
{
    if (type.equals(::cppu::UnoType< Reference< XInterface > >::get()))
    {
        // return XInterface interface
        // (resolve ambiguity by casting to lang::XTypeProvider)
        Reference< XInterface > x(
            static_cast< lang::XTypeProvider * >( this ) );
        return makeAny( x );
    }
    if (type.equals(::cppu::UnoType< Reference< lang::XTypeProvider > >::get()))
    {
        // return XInterface interface
        Reference< XInterface > x(
            static_cast< lang::XTypeProvider * >( this ) );
        return makeAny( x );
    }
    if (type.equals(::cppu::UnoType< Reference< lang::XServiceInfo > >::get()))
    {
        // return XServiceInfo interface
        Reference< lang::XServiceInfo > x(
            static_cast< lang::XServiceInfo * >( this ) );
        return makeAny( x );
    }
    if (type.equals(::cppu::UnoType< Reference< ::my_module::XSomething > >::get()))
    {
        // return sample interface
        Reference< ::my_module::XSomething > x(
            static_cast< ::my_module::XSomething * >( this ) );
        return makeAny( x );
    }
    // querying for unsupported type
    return Any();
}

void MyService1Impl::acquire()
    throw ()
{
    // thread-safe incrementation of reference count
    ::osl_incrementInterlockedCount( &m_refcount );
}

void MyService1Impl::release()
    throw ()
{
    // thread-safe decrementation of reference count
    if (0 == ::osl_decrementInterlockedCount( &m_refcount ))
    {
        delete this; // shutdown this object
    }
}

// XTypeProvider implementation
Sequence< Type > MyService1Impl::getTypes()
    throw (RuntimeException)
{
    Sequence< Type > seq( 3 );
    seq[ 0 ] = ::cppu::UnoType< Reference< lang::XTypeProvider > >::get();
    seq[ 1 ] = ::cppu::UnoType< Reference< lang::XServiceInfo > >::get();
    seq[ 2 ] = ::cppu::UnoType< Reference< ::my_module::XSomething > >::get();
    return seq;
}
Sequence< sal_Int8 > MyService1Impl::getImplementationId()
    throw (RuntimeException)
{
    static Sequence< sal_Int8 > * s_pId = 0;
    if (! s_pId)
    {
        // create unique id
        Sequence< sal_Int8 > id( 16 );
        ::rtl_createUuid( (sal_uInt8 *)id.getArray(), 0, sal_True );
        // guard initialization with some mutex
        ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() );
        if (! s_pId)
        {
            static Sequence< sal_Int8 > s_id( id );
            s_pId = &s_id;
        }
    }
    return *s_pId;
}

// XSomething implementation
OUString MyService1Impl::methodOne( OUString const & str )
    throw (RuntimeException)
{
    m_sData = str;
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
        "called methodOne() of MyService1 implementation: ") ) + m_sData;
}

OUString MyService1Impl::methodTwo( )
    throw (RuntimeException)
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
        "called methodTwo() of MyService1 implementation: ") ) + m_sData;
}

// XServiceInfo implementation
OUString MyService1Impl::getImplementationName()
    throw (RuntimeException)
{
    // unique implementation name
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
                         "my_module.my_sc_implementation.MyService1") );
}
sal_Bool MyService1Impl::supportsService( OUString const & serviceName )
    throw (RuntimeException)
{
    // this object only supports one service, so the test is simple
    return serviceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
                                         "my_module.MyService1") );
}
Sequence< OUString > MyService1Impl::getSupportedServiceNames()
    throw (RuntimeException)
{
    // this object only supports one service
    OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService1") );
    return Sequence< OUString >( &serviceName, 1 );
}

Reference< XInterface > SAL_CALL create_MyService1Impl(
    Reference< XComponentContext > const & xContext )
    SAL_THROW( () )
{
    return static_cast< lang::XTypeProvider * >( new MyService1Impl( xContext) );
}

// forward decl: implemented in service2_impl.cxx
Reference< XInterface > SAL_CALL create_MyService2Impl(
    Reference< XComponentContext > const & ) SAL_THROW( () );

}

/*
extern "C" void SAL_CALL component_getImplementationEnvironment(
    sal_Char const ** ppEnvTypeName, uno_Environment ** )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

extern "C" sal_Bool SAL_CALL component_writeInfo(
    lang::XMultiServiceFactory * xMgr, registry::XRegistryKey * xRegistry )
{
    if (xRegistry)
    {
        try
        {
            // implementation of MyService1A
            Reference< registry::XRegistryKey > xKey(
                xRegistry->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                    "my_module.my_sc_implementation.MyService1/UNO/SERVICES") ) ) );
            // subkeys denote implemented services of implementation
            xKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                "my_module.MyService1") ) );
            // implementation of MyService1B
            xKey = xRegistry->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                "my_module.my_sc_implementation.MyService2/UNO/SERVICES") ) );
            // subkeys denote implemented services of implementation
            xKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                "my_module.MyService2") ) );
            return sal_True; // success
        }
        catch (registry::InvalidRegistryException &)
        {
            // function fails if exception caught
        }
    }
    return sal_False;
}
extern "C" void * SAL_CALL component_getFactory(
    sal_Char const * implName, lang::XMultiServiceFactory * xMgr, void * )
{
    Reference< lang::XSingleComponentFactory > xFactory;
    if (0 == ::rtl_str_compare( implName, "my_module.my_sc_implementation.MyService1" ))
    {
        // create component factory for MyService1 implementation
        OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService1") );
        xFactory = ::cppu::createSingleComponentFactory(
            ::my_sc_impl::create_MyService1Impl,
            OUString( RTL_CONSTASCII_USTRINGPARAM("my_module.my_sc_implementation.MyService1") ),
            Sequence< OUString >( &serviceName, 1 ) );
    }
    else if (0 == ::rtl_str_compare( implName, "my_module.my_sc_implementation.MyService2" ))
    {
        // create component factory for MyService12 implementation
        OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService2") );
        xFactory = ::cppu::createSingleComponentFactory(
            ::my_sc_impl::create_MyService2Impl,
            OUString( RTL_CONSTASCII_USTRINGPARAM("my_module.my_sc_implementation.MyService2") ),
            Sequence< OUString >( &serviceName, 1 ) );
    }
    if (xFactory.is())
        xFactory->acquire();
    return xFactory.get(); // return acquired interface pointer or null
}
*/

<commit_msg>INTEGRATION: CWS jsc14 (1.7.14); FILE MERGED 2006/10/25 08:52:23 jsc 1.7.14.1: #i70636# remove auto generated precompiled header include<commit_after>/*************************************************************************
 *
 *  $RCSfile: service1_impl.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2006-11-06 15:00:06 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  the BSD license.
 *
 *  Copyright (c) 2003 by Sun Microsystems, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *************************************************************************/

#include <osl/interlck.h>
#include <osl/mutex.hxx>
#include <rtl/uuid.h>
#include <cppuhelper/factory.hxx>

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <my_module/XSomething.hpp>

using namespace ::rtl; // for OUString
using namespace ::com::sun::star; // for odk interfaces
using namespace ::com::sun::star::uno; // for basic types

namespace my_sc_impl
{

Sequence< OUString > SAL_CALL getSupportedServiceNames_MyService1Impl()
{
    Sequence< OUString > names(1);
    names[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("my_module.MyService1"));
    return names;
}

OUString SAL_CALL getImplementationName_MyService1Impl()
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
                         "my_module.my_sc_implementation.MyService1") );
}

class MyService1Impl
    : public ::my_module::XSomething
    , public lang::XServiceInfo
    , public lang::XTypeProvider
{
    oslInterlockedCount m_refcount;
    OUString m_sData;
    // it's good practise to store the context for further use when you use
    // other UNO API's in your implementation
    Reference< XComponentContext > m_xContext;
public:
    inline MyService1Impl(Reference< XComponentContext > const & xContext) throw ()
        : m_refcount( 0 ),
          m_xContext(xContext)
        {}

    virtual ~MyService1Impl() {}

    // XInterface
    virtual Any SAL_CALL queryInterface( Type const & type )
        throw (RuntimeException);
    virtual void SAL_CALL acquire()
        throw ();
    virtual void SAL_CALL release()
        throw ();
    // XTypeProvider
    virtual Sequence< Type > SAL_CALL getTypes()
        throw (RuntimeException);
    virtual Sequence< sal_Int8 > SAL_CALL getImplementationId()
        throw (RuntimeException);
    // XSomething
    virtual OUString SAL_CALL methodOne( OUString const & str )
        throw (RuntimeException);
    virtual OUString SAL_CALL methodTwo( )
        throw (RuntimeException);
    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName()
        throw (RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName )
        throw (RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
        throw (RuntimeException);
};

// XInterface implementation
Any MyService1Impl::queryInterface( Type const & type )
    throw (RuntimeException)
{
    if (type.equals(::cppu::UnoType< Reference< XInterface > >::get()))
    {
        // return XInterface interface
        // (resolve ambiguity by casting to lang::XTypeProvider)
        Reference< XInterface > x(
            static_cast< lang::XTypeProvider * >( this ) );
        return makeAny( x );
    }
    if (type.equals(::cppu::UnoType< Reference< lang::XTypeProvider > >::get()))
    {
        // return XInterface interface
        Reference< XInterface > x(
            static_cast< lang::XTypeProvider * >( this ) );
        return makeAny( x );
    }
    if (type.equals(::cppu::UnoType< Reference< lang::XServiceInfo > >::get()))
    {
        // return XServiceInfo interface
        Reference< lang::XServiceInfo > x(
            static_cast< lang::XServiceInfo * >( this ) );
        return makeAny( x );
    }
    if (type.equals(::cppu::UnoType< Reference< ::my_module::XSomething > >::get()))
    {
        // return sample interface
        Reference< ::my_module::XSomething > x(
            static_cast< ::my_module::XSomething * >( this ) );
        return makeAny( x );
    }
    // querying for unsupported type
    return Any();
}

void MyService1Impl::acquire()
    throw ()
{
    // thread-safe incrementation of reference count
    ::osl_incrementInterlockedCount( &m_refcount );
}

void MyService1Impl::release()
    throw ()
{
    // thread-safe decrementation of reference count
    if (0 == ::osl_decrementInterlockedCount( &m_refcount ))
    {
        delete this; // shutdown this object
    }
}

// XTypeProvider implementation
Sequence< Type > MyService1Impl::getTypes()
    throw (RuntimeException)
{
    Sequence< Type > seq( 3 );
    seq[ 0 ] = ::cppu::UnoType< Reference< lang::XTypeProvider > >::get();
    seq[ 1 ] = ::cppu::UnoType< Reference< lang::XServiceInfo > >::get();
    seq[ 2 ] = ::cppu::UnoType< Reference< ::my_module::XSomething > >::get();
    return seq;
}
Sequence< sal_Int8 > MyService1Impl::getImplementationId()
    throw (RuntimeException)
{
    static Sequence< sal_Int8 > * s_pId = 0;
    if (! s_pId)
    {
        // create unique id
        Sequence< sal_Int8 > id( 16 );
        ::rtl_createUuid( (sal_uInt8 *)id.getArray(), 0, sal_True );
        // guard initialization with some mutex
        ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() );
        if (! s_pId)
        {
            static Sequence< sal_Int8 > s_id( id );
            s_pId = &s_id;
        }
    }
    return *s_pId;
}

// XSomething implementation
OUString MyService1Impl::methodOne( OUString const & str )
    throw (RuntimeException)
{
    m_sData = str;
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
        "called methodOne() of MyService1 implementation: ") ) + m_sData;
}

OUString MyService1Impl::methodTwo( )
    throw (RuntimeException)
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
        "called methodTwo() of MyService1 implementation: ") ) + m_sData;
}

// XServiceInfo implementation
OUString MyService1Impl::getImplementationName()
    throw (RuntimeException)
{
    // unique implementation name
    return OUString( RTL_CONSTASCII_USTRINGPARAM(
                         "my_module.my_sc_implementation.MyService1") );
}
sal_Bool MyService1Impl::supportsService( OUString const & serviceName )
    throw (RuntimeException)
{
    // this object only supports one service, so the test is simple
    return serviceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
                                         "my_module.MyService1") );
}
Sequence< OUString > MyService1Impl::getSupportedServiceNames()
    throw (RuntimeException)
{
    // this object only supports one service
    OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService1") );
    return Sequence< OUString >( &serviceName, 1 );
}

Reference< XInterface > SAL_CALL create_MyService1Impl(
    Reference< XComponentContext > const & xContext )
    SAL_THROW( () )
{
    return static_cast< lang::XTypeProvider * >( new MyService1Impl( xContext) );
}

// forward decl: implemented in service2_impl.cxx
Reference< XInterface > SAL_CALL create_MyService2Impl(
    Reference< XComponentContext > const & ) SAL_THROW( () );

}

/*
extern "C" void SAL_CALL component_getImplementationEnvironment(
    sal_Char const ** ppEnvTypeName, uno_Environment ** )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

extern "C" sal_Bool SAL_CALL component_writeInfo(
    lang::XMultiServiceFactory * xMgr, registry::XRegistryKey * xRegistry )
{
    if (xRegistry)
    {
        try
        {
            // implementation of MyService1A
            Reference< registry::XRegistryKey > xKey(
                xRegistry->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                    "my_module.my_sc_implementation.MyService1/UNO/SERVICES") ) ) );
            // subkeys denote implemented services of implementation
            xKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                "my_module.MyService1") ) );
            // implementation of MyService1B
            xKey = xRegistry->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                "my_module.my_sc_implementation.MyService2/UNO/SERVICES") ) );
            // subkeys denote implemented services of implementation
            xKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                "my_module.MyService2") ) );
            return sal_True; // success
        }
        catch (registry::InvalidRegistryException &)
        {
            // function fails if exception caught
        }
    }
    return sal_False;
}
extern "C" void * SAL_CALL component_getFactory(
    sal_Char const * implName, lang::XMultiServiceFactory * xMgr, void * )
{
    Reference< lang::XSingleComponentFactory > xFactory;
    if (0 == ::rtl_str_compare( implName, "my_module.my_sc_implementation.MyService1" ))
    {
        // create component factory for MyService1 implementation
        OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService1") );
        xFactory = ::cppu::createSingleComponentFactory(
            ::my_sc_impl::create_MyService1Impl,
            OUString( RTL_CONSTASCII_USTRINGPARAM("my_module.my_sc_implementation.MyService1") ),
            Sequence< OUString >( &serviceName, 1 ) );
    }
    else if (0 == ::rtl_str_compare( implName, "my_module.my_sc_implementation.MyService2" ))
    {
        // create component factory for MyService12 implementation
        OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService2") );
        xFactory = ::cppu::createSingleComponentFactory(
            ::my_sc_impl::create_MyService2Impl,
            OUString( RTL_CONSTASCII_USTRINGPARAM("my_module.my_sc_implementation.MyService2") ),
            Sequence< OUString >( &serviceName, 1 ) );
    }
    if (xFactory.is())
        xFactory->acquire();
    return xFactory.get(); // return acquired interface pointer or null
}
*/

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QDebug>
#include <qdeclarativeextensionplugin.h>

#include <qdeclarativeengine.h>
#include <qdeclarative.h>
#include <qcontactmanager.h>
#include <qcontactdetails.h>
#include "qdeclarativecontactimageprovider_p.h"

QTM_USE_NAMESPACE

// This is run in a low priority thread.
QImage ContactThumbnailImageProvider::requestImage(const QString &id, QSize *size, const QSize &req_size)
{
    if (m_thumbnails.contains(id)) {
        if (size)
            *size = req_size;
        return m_thumbnails.value(id).scaled(req_size);
    }

    /* url format:
        image://thumbnail/{manager.contactid}
     */

    QString managerName = id.split('.').first();
    QString localId = id.split('.').last();

    QContactManager* manager = 0;
    if (m_managers.contains(managerName)) {
        manager = m_managers.value(managerName);
    } else {
        manager = new QContactManager(managerName);
        m_managers.insert(managerName, manager);
    }

    QContact c = manager->contact(localId.toInt());

    QImage image(
            req_size.width() > 0 ? req_size.width() : 100,
            req_size.height() > 0 ? req_size.height() : 50,
            QImage::Format_RGB32);

    QContactThumbnail t = c.detail<QContactThumbnail>();
    if (!t.thumbnail().isNull()) {
        image = t.thumbnail().scaled(image.size());
    } else {
        QContactAvatar a = c.detail<QContactAvatar>();
        QString imageUrl = a.imageUrl().isEmpty()? QLatin1String(":/default.svg") : a.imageUrl().toString();
        image.load(imageUrl);
    }

    if (size)
        *size = image.size();

    m_thumbnails.insert(id, image);

    return image;
}
ContactThumbnailImageProvider::ContactThumbnailImageProvider()
    :QDeclarativeImageProvider(QDeclarativeImageProvider::Image)
{

}

ContactThumbnailImageProvider::~ContactThumbnailImageProvider()
{
    foreach(const QString& name, m_managers.keys()) {
        delete m_managers.value(name);
    }

    m_managers.clear();
}

<commit_msg>Fix QTMOBILITY-1220:qmlcontacts does not show thumbnail properly<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QDebug>
#include <qdeclarativeextensionplugin.h>

#include <qdeclarativeengine.h>
#include <qdeclarative.h>
#include <qcontactmanager.h>
#include <qcontactdetails.h>
#include "qdeclarativecontactimageprovider_p.h"

QTM_USE_NAMESPACE

// This is run in a low priority thread.
QImage ContactThumbnailImageProvider::requestImage(const QString &id, QSize *size, const QSize &req_size)
{
    if (m_thumbnails.contains(id)) {
        if (size)
            *size = req_size;
        return m_thumbnails.value(id).scaled(req_size);
    }

    /* url format:
        image://thumbnail/{managerUri.contactid}
     */

    QString managerUri = id.split('.').first();
    QString localId = id.split('.').last();

    QContactManager* manager = 0;
    if (m_managers.contains(managerUri)) {
        manager = m_managers.value(managerUri);
    } else {
        manager = QContactManager::fromUri(managerUri);
        m_managers.insert(managerUri, manager);
    }

    QContact c = manager->contact(localId.toInt());

    QImage image(
            req_size.width() > 0 ? req_size.width() : 100,
            req_size.height() > 0 ? req_size.height() : 50,
            QImage::Format_RGB32);

    QContactThumbnail t = c.detail<QContactThumbnail>();
    if (!t.thumbnail().isNull()) {
        image = t.thumbnail().scaled(image.size());
    } else {
        QContactAvatar a = c.detail<QContactAvatar>();
        QString imageUrl = a.imageUrl().isEmpty()? QLatin1String(":/default.svg") : a.imageUrl().toString();
        image.load(imageUrl);
    }

    if (size)
        *size = image.size();

    m_thumbnails.insert(id, image);

    return image;
}
ContactThumbnailImageProvider::ContactThumbnailImageProvider()
    :QDeclarativeImageProvider(QDeclarativeImageProvider::Image)
{

}

ContactThumbnailImageProvider::~ContactThumbnailImageProvider()
{
    foreach(const QString& name, m_managers.keys()) {
        delete m_managers.value(name);
    }

    m_managers.clear();
}

<|endoftext|>


<commit_before>#include "parentwlxwindow.h"

#include "wlx_interfaces.h"

#include <QApplication>
#include <QLabel>
#include <QSet>
#include <QTimer>
#include <QVBoxLayout>

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QWindow>
#define QT_WA(unicode, ansi) unicode
#endif

static LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  ParentWlxWindow* tcmdWin = ParentWlxWindow::getByHandle(hWnd);
  if (tcmdWin)
  {
    // choice of WndProc
    WNDPROC proc = tcmdWin->isKeyboardExclusive() ? tcmdWin->origWndProc() :
                                                    tcmdWin->listerWndProc();

    QSet<UINT> keyEvents;
    keyEvents.insert(WM_KEYDOWN);
    keyEvents.insert(WM_KEYUP);
    keyEvents.insert(WM_DEADCHAR);
    keyEvents.insert(WM_SYSDEADCHAR);
    keyEvents.insert(WM_CHAR);
    keyEvents.insert(WM_UNICHAR);
    keyEvents.insert(WM_HOTKEY);

    if (keyEvents.contains(Msg))
    {
      // reload
      switch(wParam)
      {
      case VK_F2:
        tcmdWin->reloadWidget();
        break;
      case VK_ESCAPE:
        // set proc to Lister
        proc = tcmdWin->listerWndProc();
        break;
      default:
        break;
      }
    }
    else
    {
      // if Msg is not WM_KEYUP then proc should be ListerWndProc
      proc = tcmdWin->listerWndProc();
    }

    return CallWindowProc(proc, hWnd, Msg, wParam, lParam);
  }

  return E_FAIL;
}

// returns S_OK for all events
static LRESULT CALLBACK DummyWndProc(HWND /*hWnd*/, UINT /*Msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
{
  return S_OK;
}

ParentWlxWindow::ParentWlxWindow(const Interface& keeper, WId hParentWin) :
  QWidget(),
  m_keeper(keeper),
  m_keyboardExclusive(false),
  m_origWndProc((WNDPROC)GetWindowLongPtr((HWND)winId(), GWLP_WNDPROC)),
  m_listerWndProc(NULL),
  m_firstShowTimer(new QTimer(this)),
  m_childWindow(NULL)
{
  // keep the pointer to this into GWLP_USERDATA
  SetWindowLongPtr((HWND)winId(), GWLP_USERDATA, (LONG_PTR)this);

  setNativeParent(hParentWin);

  setAttribute(Qt::WA_DeleteOnClose, true);

  // layout
  QVBoxLayout* lay = new QVBoxLayout(this);
  lay->setContentsMargins(0,0,0,0);
  lay->setSpacing(0);
  setLayout(lay);
}

ParentWlxWindow::~ParentWlxWindow()
{
  releaseChild();

  // set previous window proc
  WNDPROC proc = m_listerWndProc ? m_listerWndProc : m_origWndProc;
  _assert(proc != WndProc);
  SetWindowLongPtr((HWND)winId(), GWLP_WNDPROC, (LONG_PTR)proc);
  m_listerWndProc = NULL;
  m_origWndProc = NULL;
}

void ParentWlxWindow::setChildWindow(IAbstractWlxWindow* childWindow)
{
  releaseChild();

  QWidget* w = childWindow->widget();
  _assert(w);
  if (w)
  {
    m_childWindow = childWindow;
    layout()->addWidget(w);
    m_childWindow->initEmbedded();
    _log("Window is embedded");
    w->show();
  }
  else
  {
    layout()->addWidget(new QLabel(QString("Cannot cast IAbstractWlxWindow* to QWidget*")));
    _log("Window is NOT embedded. Cannot cast to QWidget*.");
  }
}

ParentWlxWindow* ParentWlxWindow::getByHandle(HWND hwnd)
{
   QWidget* p = (QWidget*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
   return qobject_cast<ParentWlxWindow*> (p);
}

void ParentWlxWindow::reloadWidget()
{
  _assert(m_childWindow);
  if (m_childWindow)
  {
    m_childWindow->reload();
  }
}

void ParentWlxWindow::releaseChild()
{
  if (m_childWindow)
  {
    // clear layout
    while(layout()->count())
    {
      layout()->takeAt(0);
    }

    m_childWindow->widget()->deleteLater();
    _log(QString("Child window destroyed: ") + QString::number((quint64)m_childWindow, 16));
    m_childWindow = NULL;
  }
}

void ParentWlxWindow::setNativeParent(WId hParentWin)
{
  // make the widget window style be WS_CHILD so SetParent will work
  SetWindowLongPtr((HWND)winId(), GWL_STYLE,
                   (hParentWin ? WS_CHILD : WS_POPUP) |
                   WS_CLIPCHILDREN |
                   WS_CLIPSIBLINGS  /*|
                   WS_EX_NOPARENTNOTIFY*/);

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
  QWindow* window = windowHandle();
  window->setProperty("_q_embedded_native_parent_handle", hParentWin ? (WId)hParentWin : QVariant());
  SetParent((HWND)winId(), (HWND)hParentWin);
  window->setFlags(Qt::FramelessWindowHint);
#else
  SetParent(winId(), (HWND)hParentWin);
#endif

  QEvent e(QEvent::EmbeddingControl);
  QApplication::sendEvent(this, &e);
}

WId ParentWlxWindow::nativeParent() const
{
  return (WId)GetAncestor((HWND)winId(), GA_PARENT);
}

void ParentWlxWindow::showEvent(QShowEvent* e)
{
  QWidget::showEvent(e);

  connect(m_firstShowTimer, &QTimer::timeout, this, &ParentWlxWindow::onFirstShowTimer);
  m_firstShowTimer->start(200);
}

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
bool ParentWlxWindow::nativeEvent(const QByteArray&, void* message, long* /*result*/)
#else
bool ParentWlxWindow::winEvent(MSG* msg, long* /*result*/)
#endif
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
  MSG *msg = (MSG *)message;
#endif
  if (msg->message == WM_DESTROY)
  {
    close();
  }

  return false;
}

void ParentWlxWindow::onFirstShowTimer()
{
  WNDPROC proc = (WNDPROC)GetWindowLongPtr((HWND)winId(), GWLP_WNDPROC);
  if ( ( proc != m_origWndProc ) && ( ! m_listerWndProc ) )
  {
    m_listerWndProc = proc;

    // replace default window procedure
    SetWindowLongPtr((HWND)winId(), GWLP_WNDPROC, (LONG_PTR)WndProc);

    m_firstShowTimer->stop();
  }
}

void ParentWlxWindow::setListerOptions(int itemtype, int value) const
{
  PostMessage((HWND)nativeParent(), WM_COMMAND, MAKELONG(value, itemtype),(LPARAM)winId());
}

QString ParentWlxWindow::listerTitle() const
{
  if (HWND hParent = (HWND)nativeParent())
  {
    QVector<TCHAR> wStrTitle(GetWindowTextLength(hParent) + 1);
    GetWindowText(hParent, wStrTitle.data(), wStrTitle.size());
    QString title = QString::fromWCharArray(wStrTitle.constData());
    return title;
  }

  _assert_ex(false, "Parent handle is not accessible");
  return QString();
}

void ParentWlxWindow::setListerTitle(const QString& title)
{
  if (HWND hParent = (HWND)nativeParent())
  {
    QVector<TCHAR> wStrTitle(title.size() + 1);
    title.toWCharArray(wStrTitle.data());
    SetWindowText(hParent, wStrTitle.constData());
  }
  else
  {
    _assert_ex(false, "Parent handle is not accessible");
  }
}
<commit_msg>Fix duplicate reload() calls on F2 key press<commit_after>#include "parentwlxwindow.h"

#include "wlx_interfaces.h"

#include <QApplication>
#include <QLabel>
#include <QSet>
#include <QTimer>
#include <QVBoxLayout>

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QWindow>
#define QT_WA(unicode, ansi) unicode
#endif

static LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  ParentWlxWindow* tcmdWin = ParentWlxWindow::getByHandle(hWnd);
  if (tcmdWin)
  {
    // choice of WndProc
    WNDPROC proc = tcmdWin->isKeyboardExclusive() ? tcmdWin->origWndProc() :
                                                    tcmdWin->listerWndProc();

    if (WM_KEYDOWN == Msg)
    {
      switch (wParam)
      {
      case VK_F2:
        tcmdWin->reloadWidget();
        break;
      case VK_ESCAPE:
        // set proc to Lister
        proc = tcmdWin->listerWndProc();
        break;
      default:
        break;
      }
    }
    else
    {
      proc = tcmdWin->listerWndProc();
    }

    return CallWindowProc(proc, hWnd, Msg, wParam, lParam);
  }

  return E_FAIL;
}

ParentWlxWindow::ParentWlxWindow(const Interface& keeper, WId hParentWin) :
  QWidget(),
  m_keeper(keeper),
  m_keyboardExclusive(false),
  m_origWndProc((WNDPROC)GetWindowLongPtr((HWND)winId(), GWLP_WNDPROC)),
  m_listerWndProc(NULL),
  m_firstShowTimer(new QTimer(this)),
  m_childWindow(NULL)
{
  // keep the pointer to this into GWLP_USERDATA
  SetWindowLongPtr((HWND)winId(), GWLP_USERDATA, (LONG_PTR)this);

  setNativeParent(hParentWin);

  setAttribute(Qt::WA_DeleteOnClose, true);

  // layout
  QVBoxLayout* lay = new QVBoxLayout(this);
  lay->setContentsMargins(0,0,0,0);
  lay->setSpacing(0);
  setLayout(lay);
}

ParentWlxWindow::~ParentWlxWindow()
{
  releaseChild();

  // set previous window proc
  WNDPROC proc = m_listerWndProc ? m_listerWndProc : m_origWndProc;
  _assert(proc != WndProc);
  SetWindowLongPtr((HWND)winId(), GWLP_WNDPROC, (LONG_PTR)proc);
  m_listerWndProc = NULL;
  m_origWndProc = NULL;
}

void ParentWlxWindow::setChildWindow(IAbstractWlxWindow* childWindow)
{
  releaseChild();

  QWidget* w = childWindow->widget();
  _assert(w);
  if (w)
  {
    m_childWindow = childWindow;
    layout()->addWidget(w);
    m_childWindow->initEmbedded();
    _log("Window is embedded");
    w->show();
  }
  else
  {
    layout()->addWidget(new QLabel(QString("Cannot cast IAbstractWlxWindow* to QWidget*")));
    _log("Window is NOT embedded. Cannot cast to QWidget*.");
  }
}

ParentWlxWindow* ParentWlxWindow::getByHandle(HWND hwnd)
{
   QWidget* p = (QWidget*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
   return qobject_cast<ParentWlxWindow*> (p);
}

void ParentWlxWindow::reloadWidget()
{
  _assert(m_childWindow);
  if (m_childWindow)
  {
    m_childWindow->reload();
  }
}

void ParentWlxWindow::releaseChild()
{
  if (m_childWindow)
  {
    // clear layout
    while(layout()->count())
    {
      layout()->takeAt(0);
    }

    m_childWindow->widget()->deleteLater();
    _log(QString("Child window destroyed: ") + QString::number((quint64)m_childWindow, 16));
    m_childWindow = NULL;
  }
}

void ParentWlxWindow::setNativeParent(WId hParentWin)
{
  // make the widget window style be WS_CHILD so SetParent will work
  SetWindowLongPtr((HWND)winId(), GWL_STYLE,
                   (hParentWin ? WS_CHILD : WS_POPUP) |
                   WS_CLIPCHILDREN |
                   WS_CLIPSIBLINGS  /*|
                   WS_EX_NOPARENTNOTIFY*/);

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
  QWindow* window = windowHandle();
  window->setProperty("_q_embedded_native_parent_handle", hParentWin ? (WId)hParentWin : QVariant());
  SetParent((HWND)winId(), (HWND)hParentWin);
  window->setFlags(Qt::FramelessWindowHint);
#else
  SetParent(winId(), (HWND)hParentWin);
#endif

  QEvent e(QEvent::EmbeddingControl);
  QApplication::sendEvent(this, &e);
}

WId ParentWlxWindow::nativeParent() const
{
  return (WId)GetAncestor((HWND)winId(), GA_PARENT);
}

void ParentWlxWindow::showEvent(QShowEvent* e)
{
  QWidget::showEvent(e);

  connect(m_firstShowTimer, &QTimer::timeout, this, &ParentWlxWindow::onFirstShowTimer);
  m_firstShowTimer->start(200);
}

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
bool ParentWlxWindow::nativeEvent(const QByteArray&, void* message, long* /*result*/)
#else
bool ParentWlxWindow::winEvent(MSG* msg, long* /*result*/)
#endif
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
  MSG *msg = (MSG *)message;
#endif
  if (msg->message == WM_DESTROY)
  {
    close();
  }

  return false;
}

void ParentWlxWindow::onFirstShowTimer()
{
  WNDPROC proc = (WNDPROC)GetWindowLongPtr((HWND)winId(), GWLP_WNDPROC);
  if ( ( proc != m_origWndProc ) && ( ! m_listerWndProc ) )
  {
    m_listerWndProc = proc;

    // replace default window procedure
    SetWindowLongPtr((HWND)winId(), GWLP_WNDPROC, (LONG_PTR)WndProc);

    m_firstShowTimer->stop();
  }
}

void ParentWlxWindow::setListerOptions(int itemtype, int value) const
{
  PostMessage((HWND)nativeParent(), WM_COMMAND, MAKELONG(value, itemtype),(LPARAM)winId());
}

QString ParentWlxWindow::listerTitle() const
{
  if (HWND hParent = (HWND)nativeParent())
  {
    QVector<TCHAR> wStrTitle(GetWindowTextLength(hParent) + 1);
    GetWindowText(hParent, wStrTitle.data(), wStrTitle.size());
    QString title = QString::fromWCharArray(wStrTitle.constData());
    return title;
  }

  _assert_ex(false, "Parent handle is not accessible");
  return QString();
}

void ParentWlxWindow::setListerTitle(const QString& title)
{
  if (HWND hParent = (HWND)nativeParent())
  {
    QVector<TCHAR> wStrTitle(title.size() + 1);
    title.toWCharArray(wStrTitle.data());
    SetWindowText(hParent, wStrTitle.constData());
  }
  else
  {
    _assert_ex(false, "Parent handle is not accessible");
  }
}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

#define PRINT_INFO
//#define DEBUG
//#define DEBUG2

#include "virtionet.hpp"
#include <net/packet.hpp>
#include <kernel/irq_manager.hpp>
#include <kernel/syscalls.hpp>
#include <hw/pci.hpp>
#include <cstdlib>
#include <malloc.h>
#include <string.h>

//#define NO_DEFERRED_KICK
#ifndef NO_DEFERRED_KICK
static std::vector<VirtioNet*> deferred_devices;
static uint8_t deferred_intr;
#endif

using namespace net;

void VirtioNet::get_config() {
  Virtio::get_config(&_conf, _config_length);
}

VirtioNet::VirtioNet(hw::PCI_Device& d)
  : Virtio(d),
    Link(Link_protocol{{this, &VirtioNet::transmit}, mac()},
        std::max(2048u, queue_size(0) * 2), sizeof(net::Packet) + sizeof(virtio_net_hdr) + MTU()),
    packets_rx_{Statman::get().create(Stat::UINT64, device_name() + ".packets_rx").get_uint64()},
    packets_tx_{Statman::get().create(Stat::UINT64, device_name() + ".packets_tx").get_uint64()}
{
  INFO("VirtioNet", "Driver initializing");
  // this must be true, otherwise packets will be created incorrectly
  assert(sizeof(virtio_net_hdr) <= sizeof(Packet));

  uint32_t needed_features = 0
    | (1 << VIRTIO_NET_F_MAC)
    | (1 << VIRTIO_NET_F_STATUS)
    ;//| (1 << VIRTIO_NET_F_MRG_RXBUF); //Merge RX Buffers (Everything i 1 buffer)
  uint32_t wanted_features = needed_features;
  negotiate_features(wanted_features);

  CHECK ((features() & needed_features) == needed_features,
         "Negotiated needed features");

  CHECK ((features() & wanted_features) == wanted_features,
         "Negotiated wanted features");

  CHECK(features() & (1 << VIRTIO_NET_F_CSUM),
        "Device handles packets w. partial checksum");

  CHECK(features() & (1 << VIRTIO_NET_F_GUEST_CSUM),
        "Guest handles packets w. partial checksum");

  CHECK(features() & (1 << VIRTIO_NET_F_CTRL_VQ),
        "There's a control queue");

  CHECK(features() & (1 << VIRTIO_F_ANY_LAYOUT),
        "Queue can handle any header/data layout");

  CHECK(features() & (1 << VIRTIO_F_RING_INDIRECT_DESC),
        "We can use indirect descriptors");

  CHECK(features() & (1 << VIRTIO_F_RING_EVENT_IDX),
        "There's a Ring Event Index to use");

  CHECK(features() & (1 << VIRTIO_NET_F_MQ),
        "There are multiple queue pairs");

  if (features() & (1 << VIRTIO_NET_F_MQ))
    printf("\t\t* max_virtqueue_pairs: 0x%x \n",_conf.max_virtq_pairs);

  CHECK(features() & (1 << VIRTIO_NET_F_MRG_RXBUF),
        "Merge RX buffers");

  /** RX que is 0, TX Queue is 1 - Virtio Std. §5.1.2  */
  new (&rx_q) Virtio::Queue(queue_size(0),0,iobase());
  new (&tx_q) Virtio::Queue(queue_size(1),1,iobase());
  new (&ctrl_q) Virtio::Queue(queue_size(2),2,iobase());

  // Step 1 - Initialize RX/TX queues
  auto success = assign_queue(0, (uint32_t)rx_q.queue_desc());
  CHECK(success, "RX queue (%u) assigned (0x%x) to device",
        rx_q.size(), (uint32_t)rx_q.queue_desc());

  success = assign_queue(1, (uint32_t)tx_q.queue_desc());
  CHECK(success, "TX queue (%u) assigned (0x%x) to device",
        tx_q.size(), (uint32_t)tx_q.queue_desc());

  // Step 2 - Initialize Ctrl-queue if it exists
  if (features() & (1 << VIRTIO_NET_F_CTRL_VQ)) {
    success = assign_queue(2, (uint32_t)tx_q.queue_desc());
    CHECK(success, "CTRL queue (%u) assigned (0x%x) to device",
          ctrl_q.size(), (uint32_t)ctrl_q.queue_desc());
  }

  // Step 3 - Fill receive queue with buffers
  // DEBUG: Disable
  INFO("VirtioNet", "Adding %u receive buffers of size %u",
       rx_q.size(), bufsize());

  for (int i = 0; i < rx_q.size(); i++) add_receive_buffer();

  // Step 4 - If there are many queues, we should negotiate the number.
  // Set config length, based on whether there are multiple queues
  if (features() & (1 << VIRTIO_NET_F_MQ))
    _config_length = sizeof(config);
  else
    _config_length = sizeof(config) - sizeof(uint16_t);
  // @todo: Specify how many queues we're going to use.

  // Step 5 - get the mac address (we're demanding this feature)
  // Step 6 - get the status - demanding this as well.
  // Getting the MAC + status
  get_config();

  CHECK(_conf.mac.major > 0, "Valid Mac address: %s",
        _conf.mac.str().c_str());

  // Step 7 - 9 - GSO: @todo Not using GSO features yet.

  // Signal setup complete.
  setup_complete((features() & needed_features) == needed_features);
  CHECK((features() & needed_features) == needed_features, "Signalled driver OK");

  // Hook up interrupts
  if (has_msix())
  {
    assert(get_msix_vectors() >= 3);
    // for now use service queues, otherwise stress test fails
    auto recv_del(delegate<void()>{this, &VirtioNet::msix_recv_handler});
    auto xmit_del(delegate<void()>{this, &VirtioNet::msix_xmit_handler});
    auto conf_del(delegate<void()>{this, &VirtioNet::msix_conf_handler});

    // update BSP IDT
    IRQ_manager::get().subscribe(irq() + 0, recv_del);
    IRQ_manager::get().subscribe(irq() + 1, xmit_del);
    IRQ_manager::get().subscribe(irq() + 2, conf_del);
  }
  else
  {
    assert(0 && "Legacy IRQs not supported");
  }

#ifndef NO_DEFERRED_KICK
  static bool init_deferred = false;
  if (!init_deferred) {
    init_deferred = true;
    deferred_intr = IRQ_manager::get().get_next_msix_irq();
    IRQ_manager::get().subscribe(deferred_intr, handle_deferred_devices);
  }
#endif

  // Done
  INFO("VirtioNet", "Driver initialization complete");
  CHECK(_conf.status & 1, "Link up\n");
  rx_q.kick();
}

void VirtioNet::msix_conf_handler()
{
  debug("\t <VirtioNet> Configuration change:\n");

  // Getting the MAC + status
  debug("\t             Old status: 0x%x\n",_conf.status);
  get_config();
  debug("\t             New status: 0x%x \n",_conf.status);
}
void VirtioNet::msix_recv_handler()
{
  bool dequeued_rx = false;
  rx_q.disable_interrupts();
  // handle incoming packets as long as bufstore has available buffers
  while (rx_q.new_incoming() && bufstore().available() > 1)
  {
    auto res = rx_q.dequeue();
    auto pckt_ptr = recv_packet(res.data(), res.size());
    Link::receive(std::move(pckt_ptr));

    // Requeue a new buffer
    add_receive_buffer();

    dequeued_rx = true;

    // Stat increase packets received
    packets_rx_++;
  }
  rx_q.enable_interrupts();
  if (dequeued_rx)
    rx_q.kick();
}
void VirtioNet::msix_xmit_handler()
{
  bool dequeued_tx = false;
  tx_q.disable_interrupts();
  // Do one TX-packet
  while (tx_q.new_incoming())
  {
    auto res = tx_q.dequeue();
    assert(res.data());
    // get packet offset, and call destructor
    auto* packet = (net::Packet*) (res.data() - sizeof(net::Packet));
    packet->~Packet(); // call destructor on Packet to release it

    dequeued_tx = true;
  }

  // If we have a transmit queue, eat from it, otherwise let the stack know we
  // have increased transmit capacity
  if (dequeued_tx) {
    debug("<VirtioNet>%i dequeued, transmitting backlog\n", dequeued_tx);

    // transmit as much as possible from the buffer
    if (transmit_queue_){
      transmit(std::move(transmit_queue_));
    }

    // If we now emptied the buffer, offer packets to stack
    if (!transmit_queue_ && tx_q.num_free() > 1)
        transmit_queue_available_event_(tx_q.num_free() / 2);
  }
}

void VirtioNet::add_receive_buffer()
{
  auto* pkt = bufstore().get_buffer();
  // offset pointer to virtionet header
  auto* vnet = pkt + sizeof(Packet);

  Token token2 { {vnet, sizeof(virtio_net_hdr) + MTU()}, Token::IN };

  std::array<Token, 1> tokens {{ token2 }};
  rx_q.enqueue(tokens);
}

net::Packet_ptr
VirtioNet::recv_packet(uint8_t* data, uint16_t size)
{
  auto* ptr = (net::Packet*) (data - sizeof(net::Packet));
#ifdef DEBUG
  assert(bufstore().is_from_pool((uint8_t*) ptr));
  assert(bufstore().is_buffer((uint8_t*) ptr));
#endif
  new (ptr) net::Packet(MTU(), size - sizeof(virtio_net_hdr), sizeof(virtio_net_hdr), &bufstore());
  return net::Packet_ptr(ptr);
}
net::Packet_ptr
VirtioNet::create_packet(uint16_t size)
{
  auto* ptr = (net::Packet*) bufstore().get_buffer();
  new (ptr) net::Packet(MTU(), size, sizeof(virtio_net_hdr), &bufstore());
  return net::Packet_ptr(ptr);
}

void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){
  if (transmit_queue_)
    transmit_queue_->chain(std::move(pckt));
  else
    transmit_queue_ = std::move(pckt);

#ifdef DEBUG
  size_t chain_length = 1;
  auto* next = transmit_queue_->tail();
  while (next) {
    chain_length++;
    next = next->tail();
  }
#endif

  debug("Buffering, %i packets chained \n", chain_length);
}

void VirtioNet::transmit(net::Packet_ptr pckt) {
  /** @note We have to send a virtio header first, then the packet.

      From Virtio std. §5.1.6.6:
      "When using legacy interfaces, transitional drivers which have not
      negotiated VIRTIO_F_ANY_LAYOUT MUST use a single descriptor for the struct
      virtio_net_hdr on both transmit and receive, with the network data in the
      following descriptors."

      VirtualBox *does not* accept ANY_LAYOUT, while Qemu does, so this is to
      support VirtualBox
  */
  int transmitted = 0;
  net::Packet_ptr tail = std::move(pckt);

  // Transmit all we can directly
  while (tx_q.num_free() and tail) {
    debug("%i tokens left in TX queue \n", tx_q.num_free());
    // next in line
    auto next = tail->detach_tail();
    // write data to network
    // explicitly release the data to prevent destructor being called
    enqueue(tail.release());
    tail = std::move(next);
    transmitted++;
    // Stat increase packets transmitted
    packets_tx_++;

    if (!tail) break;
  }

  // Notify virtio about new packets
  if (LIKELY(transmitted)) {
    begin_deferred_kick();
  }

  // Buffer the rest
  if (UNLIKELY(tail)) {
    debug("Buffering remaining packets..\n");
    add_to_tx_buffer(std::move(tail));
  }
}

void VirtioNet::enqueue(net::Packet* pckt)
{
  auto* hdr = pckt->buffer() - sizeof(virtio_net_hdr);

  Token token1 {{ hdr, sizeof(virtio_net_hdr)}, Token::OUT };
  Token token2 {{ pckt->buffer(), pckt->size()}, Token::OUT };

  std::array<Token, 2> tokens {{ token1, token2 }};

  // Enqueue scatterlist, 2 pieces readable, 0 writable.
  tx_q.enqueue(tokens);
}

void VirtioNet::begin_deferred_kick()
{
#ifdef NO_DEFERRED_KICK
  tx_q.enable_interrupts();
  tx_q.kick();
#else
  if (!deferred_kick) {
    deferred_kick = true;
    deferred_devices.push_back(this);
    IRQ_manager::get().register_irq(deferred_intr);
  }
#endif
}
void VirtioNet::handle_deferred_devices()
{
#ifndef NO_DEFERRED_KICK
  for (auto* dev : deferred_devices) {
    // kick transmitq
    dev->deferred_kick = false;
    dev->tx_q.enable_interrupts();
    dev->tx_q.kick();
  }
  deferred_devices.clear();
#endif
}

void VirtioNet::deactivate()
{
  /// disable interrupts on virtio queues
  rx_q.disable_interrupts();
  tx_q.disable_interrupts();
  ctrl_q.disable_interrupts();

  /// mask off MSI-X vectors
  if (has_msix())
      deactivate_msix();
}

#include <kernel/pci_manager.hpp>

/** Register VirtioNet's driver factory at the PCI_manager */
static struct Autoreg_virtionet {
  Autoreg_virtionet() {
    PCI_manager::register_driver<hw::Nic>(hw::PCI_Device::VENDOR_VIRTIO, 0x1000, &VirtioNet::new_instance);
  }
} autoreg_virtionet;
<commit_msg>virtionet: Undo combine receive tokens<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

#define PRINT_INFO
//#define DEBUG
//#define DEBUG2

#include "virtionet.hpp"
#include <net/packet.hpp>
#include <kernel/irq_manager.hpp>
#include <kernel/syscalls.hpp>
#include <hw/pci.hpp>
#include <cstdlib>
#include <malloc.h>
#include <string.h>

//#define NO_DEFERRED_KICK
#ifndef NO_DEFERRED_KICK
static std::vector<VirtioNet*> deferred_devices;
static uint8_t deferred_intr;
#endif

using namespace net;

void VirtioNet::get_config() {
  Virtio::get_config(&_conf, _config_length);
}

VirtioNet::VirtioNet(hw::PCI_Device& d)
  : Virtio(d),
    Link(Link_protocol{{this, &VirtioNet::transmit}, mac()},
        std::max(2048u, queue_size(0) * 2), sizeof(net::Packet) + sizeof(virtio_net_hdr) + MTU()),
    packets_rx_{Statman::get().create(Stat::UINT64, device_name() + ".packets_rx").get_uint64()},
    packets_tx_{Statman::get().create(Stat::UINT64, device_name() + ".packets_tx").get_uint64()}
{
  INFO("VirtioNet", "Driver initializing");
  // this must be true, otherwise packets will be created incorrectly
  assert(sizeof(virtio_net_hdr) <= sizeof(Packet));

  uint32_t needed_features = 0
    | (1 << VIRTIO_NET_F_MAC)
    | (1 << VIRTIO_NET_F_STATUS)
    ;//| (1 << VIRTIO_NET_F_MRG_RXBUF); //Merge RX Buffers (Everything i 1 buffer)
  uint32_t wanted_features = needed_features;
  negotiate_features(wanted_features);

  CHECK ((features() & needed_features) == needed_features,
         "Negotiated needed features");

  CHECK ((features() & wanted_features) == wanted_features,
         "Negotiated wanted features");

  CHECK(features() & (1 << VIRTIO_NET_F_CSUM),
        "Device handles packets w. partial checksum");

  CHECK(features() & (1 << VIRTIO_NET_F_GUEST_CSUM),
        "Guest handles packets w. partial checksum");

  CHECK(features() & (1 << VIRTIO_NET_F_CTRL_VQ),
        "There's a control queue");

  CHECK(features() & (1 << VIRTIO_F_ANY_LAYOUT),
        "Queue can handle any header/data layout");

  CHECK(features() & (1 << VIRTIO_F_RING_INDIRECT_DESC),
        "We can use indirect descriptors");

  CHECK(features() & (1 << VIRTIO_F_RING_EVENT_IDX),
        "There's a Ring Event Index to use");

  CHECK(features() & (1 << VIRTIO_NET_F_MQ),
        "There are multiple queue pairs");

  if (features() & (1 << VIRTIO_NET_F_MQ))
    printf("\t\t* max_virtqueue_pairs: 0x%x \n",_conf.max_virtq_pairs);

  CHECK(features() & (1 << VIRTIO_NET_F_MRG_RXBUF),
        "Merge RX buffers");

  /** RX que is 0, TX Queue is 1 - Virtio Std. §5.1.2  */
  new (&rx_q) Virtio::Queue(queue_size(0),0,iobase());
  new (&tx_q) Virtio::Queue(queue_size(1),1,iobase());
  new (&ctrl_q) Virtio::Queue(queue_size(2),2,iobase());

  // Step 1 - Initialize RX/TX queues
  auto success = assign_queue(0, (uint32_t)rx_q.queue_desc());
  CHECK(success, "RX queue (%u) assigned (0x%x) to device",
        rx_q.size(), (uint32_t)rx_q.queue_desc());

  success = assign_queue(1, (uint32_t)tx_q.queue_desc());
  CHECK(success, "TX queue (%u) assigned (0x%x) to device",
        tx_q.size(), (uint32_t)tx_q.queue_desc());

  // Step 2 - Initialize Ctrl-queue if it exists
  if (features() & (1 << VIRTIO_NET_F_CTRL_VQ)) {
    success = assign_queue(2, (uint32_t)tx_q.queue_desc());
    CHECK(success, "CTRL queue (%u) assigned (0x%x) to device",
          ctrl_q.size(), (uint32_t)ctrl_q.queue_desc());
  }

  // Step 3 - Fill receive queue with buffers
  // DEBUG: Disable
  INFO("VirtioNet", "Adding %u receive buffers of size %u",
       rx_q.size() / 2, bufsize());

  for (int i = 0; i < rx_q.size() / 2; i++) add_receive_buffer();

  // Step 4 - If there are many queues, we should negotiate the number.
  // Set config length, based on whether there are multiple queues
  if (features() & (1 << VIRTIO_NET_F_MQ))
    _config_length = sizeof(config);
  else
    _config_length = sizeof(config) - sizeof(uint16_t);
  // @todo: Specify how many queues we're going to use.

  // Step 5 - get the mac address (we're demanding this feature)
  // Step 6 - get the status - demanding this as well.
  // Getting the MAC + status
  get_config();

  CHECK(_conf.mac.major > 0, "Valid Mac address: %s",
        _conf.mac.str().c_str());

  // Step 7 - 9 - GSO: @todo Not using GSO features yet.

  // Signal setup complete.
  setup_complete((features() & needed_features) == needed_features);
  CHECK((features() & needed_features) == needed_features, "Signalled driver OK");

  // Hook up interrupts
  if (has_msix())
  {
    assert(get_msix_vectors() >= 3);
    // for now use service queues, otherwise stress test fails
    auto recv_del(delegate<void()>{this, &VirtioNet::msix_recv_handler});
    auto xmit_del(delegate<void()>{this, &VirtioNet::msix_xmit_handler});
    auto conf_del(delegate<void()>{this, &VirtioNet::msix_conf_handler});

    // update BSP IDT
    IRQ_manager::get().subscribe(irq() + 0, recv_del);
    IRQ_manager::get().subscribe(irq() + 1, xmit_del);
    IRQ_manager::get().subscribe(irq() + 2, conf_del);
  }
  else
  {
    assert(0 && "Legacy IRQs not supported");
  }

#ifndef NO_DEFERRED_KICK
  static bool init_deferred = false;
  if (!init_deferred) {
    init_deferred = true;
    deferred_intr = IRQ_manager::get().get_next_msix_irq();
    IRQ_manager::get().subscribe(deferred_intr, handle_deferred_devices);
  }
#endif

  // Done
  INFO("VirtioNet", "Driver initialization complete");
  CHECK(_conf.status & 1, "Link up\n");
  rx_q.kick();
}

void VirtioNet::msix_conf_handler()
{
  debug("\t <VirtioNet> Configuration change:\n");

  // Getting the MAC + status
  debug("\t             Old status: 0x%x\n",_conf.status);
  get_config();
  debug("\t             New status: 0x%x \n",_conf.status);
}
void VirtioNet::msix_recv_handler()
{
  bool dequeued_rx = false;
  rx_q.disable_interrupts();
  // handle incoming packets as long as bufstore has available buffers
  while (rx_q.new_incoming() && bufstore().available() > 1)
  {
    auto res = rx_q.dequeue();
    auto pckt_ptr = recv_packet(res.data(), res.size());
    Link::receive(std::move(pckt_ptr));

    // Requeue a new buffer
    add_receive_buffer();

    dequeued_rx = true;

    // Stat increase packets received
    packets_rx_++;
  }
  rx_q.enable_interrupts();
  if (dequeued_rx)
    rx_q.kick();
}
void VirtioNet::msix_xmit_handler()
{
  bool dequeued_tx = false;
  tx_q.disable_interrupts();
  // Do one TX-packet
  while (tx_q.new_incoming())
  {
    auto res = tx_q.dequeue();
    assert(res.data());
    // get packet offset, and call destructor
    auto* packet = (net::Packet*) (res.data() - sizeof(net::Packet));
    packet->~Packet(); // call destructor on Packet to release it

    dequeued_tx = true;
  }

  // If we have a transmit queue, eat from it, otherwise let the stack know we
  // have increased transmit capacity
  if (dequeued_tx) {
    debug("<VirtioNet>%i dequeued, transmitting backlog\n", dequeued_tx);

    // transmit as much as possible from the buffer
    if (transmit_queue_){
      transmit(std::move(transmit_queue_));
    }

    // If we now emptied the buffer, offer packets to stack
    if (!transmit_queue_ && tx_q.num_free() > 1)
        transmit_queue_available_event_(tx_q.num_free() / 2);
  }
}

void VirtioNet::add_receive_buffer()
{
  auto* pkt = bufstore().get_buffer();
  // offset pointer to virtionet header
  auto* vnet = pkt + sizeof(Packet);

  Token token1 {{vnet, sizeof(virtio_net_hdr)}, Token::IN };
  Token token2 {{vnet + sizeof(virtio_net_hdr), MTU()}, Token::IN };

  std::array<Token, 2> tokens {{ token1, token2 }};
  rx_q.enqueue(tokens);
}

net::Packet_ptr
VirtioNet::recv_packet(uint8_t* data, uint16_t size)
{
  auto* ptr = (net::Packet*) (data - sizeof(net::Packet));
#ifdef DEBUG
  assert(bufstore().is_from_pool((uint8_t*) ptr));
  assert(bufstore().is_buffer((uint8_t*) ptr));
#endif
  new (ptr) net::Packet(MTU(), size - sizeof(virtio_net_hdr), sizeof(virtio_net_hdr), &bufstore());
  return net::Packet_ptr(ptr);
}
net::Packet_ptr
VirtioNet::create_packet(uint16_t size)
{
  auto* ptr = (net::Packet*) bufstore().get_buffer();
  new (ptr) net::Packet(MTU(), size, sizeof(virtio_net_hdr), &bufstore());
  return net::Packet_ptr(ptr);
}

void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){
  if (transmit_queue_)
    transmit_queue_->chain(std::move(pckt));
  else
    transmit_queue_ = std::move(pckt);

#ifdef DEBUG
  size_t chain_length = 1;
  auto* next = transmit_queue_->tail();
  while (next) {
    chain_length++;
    next = next->tail();
  }
#endif

  debug("Buffering, %i packets chained \n", chain_length);
}

void VirtioNet::transmit(net::Packet_ptr pckt) {
  /** @note We have to send a virtio header first, then the packet.

      From Virtio std. §5.1.6.6:
      "When using legacy interfaces, transitional drivers which have not
      negotiated VIRTIO_F_ANY_LAYOUT MUST use a single descriptor for the struct
      virtio_net_hdr on both transmit and receive, with the network data in the
      following descriptors."

      VirtualBox *does not* accept ANY_LAYOUT, while Qemu does, so this is to
      support VirtualBox
  */
  int transmitted = 0;
  net::Packet_ptr tail = std::move(pckt);

  // Transmit all we can directly
  while (tx_q.num_free() and tail) {
    debug("%i tokens left in TX queue \n", tx_q.num_free());
    // next in line
    auto next = tail->detach_tail();
    // write data to network
    // explicitly release the data to prevent destructor being called
    enqueue(tail.release());
    tail = std::move(next);
    transmitted++;
    // Stat increase packets transmitted
    packets_tx_++;

    if (!tail) break;
  }

  // Notify virtio about new packets
  if (LIKELY(transmitted)) {
    begin_deferred_kick();
  }

  // Buffer the rest
  if (UNLIKELY(tail)) {
    debug("Buffering remaining packets..\n");
    add_to_tx_buffer(std::move(tail));
  }
}

void VirtioNet::enqueue(net::Packet* pckt)
{
  auto* hdr = pckt->buffer() - sizeof(virtio_net_hdr);

  Token token1 {{ hdr, sizeof(virtio_net_hdr)}, Token::OUT };
  Token token2 {{ pckt->buffer(), pckt->size()}, Token::OUT };

  std::array<Token, 2> tokens {{ token1, token2 }};

  // Enqueue scatterlist, 2 pieces readable, 0 writable.
  tx_q.enqueue(tokens);
}

void VirtioNet::begin_deferred_kick()
{
#ifdef NO_DEFERRED_KICK
  tx_q.enable_interrupts();
  tx_q.kick();
#else
  if (!deferred_kick) {
    deferred_kick = true;
    deferred_devices.push_back(this);
    IRQ_manager::get().register_irq(deferred_intr);
  }
#endif
}
void VirtioNet::handle_deferred_devices()
{
#ifndef NO_DEFERRED_KICK
  for (auto* dev : deferred_devices) {
    // kick transmitq
    dev->deferred_kick = false;
    dev->tx_q.enable_interrupts();
    dev->tx_q.kick();
  }
  deferred_devices.clear();
#endif
}

void VirtioNet::deactivate()
{
  /// disable interrupts on virtio queues
  rx_q.disable_interrupts();
  tx_q.disable_interrupts();
  ctrl_q.disable_interrupts();

  /// mask off MSI-X vectors
  if (has_msix())
      deactivate_msix();
}

#include <kernel/pci_manager.hpp>

/** Register VirtioNet's driver factory at the PCI_manager */
static struct Autoreg_virtionet {
  Autoreg_virtionet() {
    PCI_manager::register_driver<hw::Nic>(hw::PCI_Device::VENDOR_VIRTIO, 0x1000, &VirtioNet::new_instance);
  }
} autoreg_virtionet;
<|endoftext|>


<commit_before>/*
 * Copyright 2013-2014 Jose Fonseca
 *
 * 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.1 of the License.
 *
 * 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 "tap.h"
#include "apps/wine.h"

#include <assert.h>
#include <stdlib.h>

#include <windows.h>
#include <dbghelp.h>
#include <shlwapi.h>

static bool
comparePath(const char *s1, const char *s2)
{
    if (strcmp(s1, s2) == 0) {
        return true;
    }

    s1 = PathFindFileNameA(s1);
    s2 = PathFindFileNameA(s2);

    return strcmp(s1, s2) == 0;
}

static BOOL
g_bStripped = FALSE;

static void
checkSym(HANDLE hProcess,
         PVOID pvSymbol,
         const char *szSymbolName)
{
    bool ok;

    DWORD64 dwAddr = (DWORD64)(UINT_PTR)pvSymbol;

    // Test SymFromAddr
    DWORD64 Displacement = 0;
    struct {
        SYMBOL_INFO Symbol;
        CHAR Name[256];
    } s;
    memset(&s, 0, sizeof s);
    s.Symbol.SizeOfStruct = sizeof s.Symbol;
    s.Symbol.MaxNameLen = sizeof s.Symbol.Name + sizeof s.Name;
    ok = SymFromAddr(hProcess, dwAddr, &Displacement, &s.Symbol);
    test_line(ok, "SymFromAddr(&%s)", szSymbolName);
    if (!ok) {
        test_diagnostic_last_error();
    } else {
        if (!g_bStripped) {
            ok = strcmp(s.Symbol.Name, szSymbolName) == 0;
        } else {
            // XXX: ignore differences due to demangling
            ok = strncmp(szSymbolName, s.Symbol.Name, strlen(szSymbolName)) == 0;
        }
        test_line(ok, "SymFromAddr(&%s).Name", szSymbolName);
        if (!ok) {
            test_diagnostic("Name = \"%s\" != \"%s\"",
                            s.Symbol.Name, szSymbolName);
        }
    }
}

static void
checkSymLine(HANDLE hProcess,
             PVOID pvSymbol,
             const char *szSymbolName,
             const char *szFileName,
             DWORD dwLineNumber)
{
    bool ok;

    DWORD64 dwAddr = (DWORD64)(UINT_PTR)pvSymbol;

    checkSym(hProcess, pvSymbol, szSymbolName);

    if (g_bStripped) {
        // Don't check line nos
        return;
    }

    // Test SymGetLineFromAddr64
    DWORD dwDisplacement;
    IMAGEHLP_LINE64 Line;
    ZeroMemory(&Line, sizeof Line);
    Line.SizeOfStruct = sizeof Line;
    ok = SymGetLineFromAddr64(hProcess, dwAddr, &dwDisplacement, &Line);
    test_line(ok, "SymGetLineFromAddr64(&%s)", szSymbolName);
    if (!ok) {
        test_diagnostic_last_error();
    } else {
        ok = comparePath(Line.FileName, szFileName);
        test_line(ok, "SymGetLineFromAddr64(&%s).FileName", szSymbolName);
        if (!ok) {
            test_diagnostic("FileName = \"%s\" != \"%s\"",
                            Line.FileName, szFileName);
        }
        ok = Line.LineNumber == dwLineNumber;
        test_line(ok, "SymGetLineFromAddr64(&%s).LineNumber", szSymbolName);
        if (Line.LineNumber != dwLineNumber) {
            test_diagnostic("LineNumber = %lu != %lu",
                            Line.LineNumber, dwLineNumber);
        }
    }
}

static void
    __attribute__ ((noinline))
checkCaller(HANDLE hProcess,
            const char *szSymbolName,
            const char *szFileName,
            DWORD dwLineNumber)
{
    void *addr = __builtin_return_address(0);
    checkSymLine(hProcess, addr, szSymbolName, szFileName, dwLineNumber);
}

static void
checkExport(HANDLE hProcess,
            const char *szModuleName,
            const char *szSymbolName)
{
    HMODULE hModule = GetModuleHandleA(szModuleName);
    const PVOID pvSymbol = (PVOID)GetProcAddress(hModule, szSymbolName);
    checkSym(hProcess, pvSymbol, szSymbolName);
}

static const DWORD foo_line = __LINE__; static int foo(int a, int b) {
    return a * b;
}

#define LINE_BARRIER rand();

int
main(int argc, char **argv)
{
    HANDLE hProcess = GetCurrentProcess();
    bool ok;

    if (strstr(argv[0], "test_mgwhelp_stripped")) {
        g_bStripped = TRUE;
    }

    HMODULE hMgwHelpDll = GetModuleHandleA("mgwhelp.dll");
    if (!hMgwHelpDll) {
        test_line(false, "GetModuleHandleA(\"mgwhelp.dll\")");
    } else {
        test_line(GetProcAddress(hMgwHelpDll, "SymGetOptions") != NULL, "GetProcAddress(\"SymGetOptions\")");
        test_line(GetProcAddress(hMgwHelpDll, "SymGetOptions@0") == NULL, "!GetProcAddress(\"SymGetOptions\")");
    }

    ok = SymInitialize(hProcess, "", TRUE);
    test_line(ok, "SymInitialize()");
    if (!ok) {
        test_diagnostic_last_error();
    } {
        checkSymLine(hProcess, (PVOID)&foo, "foo", __FILE__, foo_line);

        checkCaller(hProcess, "main", __FILE__, __LINE__); LINE_BARRIER

        // Test DbgHelp fallback
        // XXX: Doesn't work reliably on Wine
        if (!insideWine()) {
            checkExport(hProcess, "kernel32", "Sleep");
        }

        ok = SymCleanup(hProcess);
        test_line(ok, "SymCleanup()");
        if (!ok) {
            test_diagnostic_last_error();
        }
    }

    test_exit();
}
<commit_msg>tests: Add test for Displacement out parameter.<commit_after>/*
 * Copyright 2013-2014 Jose Fonseca
 *
 * 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.1 of the License.
 *
 * 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 "tap.h"
#include "apps/wine.h"

#include <assert.h>
#include <stdlib.h>

#include <windows.h>
#include <dbghelp.h>
#include <shlwapi.h>

static bool
comparePath(const char *s1, const char *s2)
{
    if (strcmp(s1, s2) == 0) {
        return true;
    }

    s1 = PathFindFileNameA(s1);
    s2 = PathFindFileNameA(s2);

    return strcmp(s1, s2) == 0;
}

static BOOL
g_bStripped = FALSE;

static void
checkSym(HANDLE hProcess,
         PVOID pvSymbol,
         const char *szSymbolName,
         DWORD64 dwExpectDisplacement)
{
    bool ok;

    DWORD64 dwAddr = (DWORD64)(UINT_PTR)pvSymbol;

    // Test SymFromAddr
    DWORD64 Displacement = -1;
    struct {
        SYMBOL_INFO Symbol;
        CHAR Name[256];
    } s;
    memset(&s, 0, sizeof s);
    s.Symbol.SizeOfStruct = sizeof s.Symbol;
    s.Symbol.MaxNameLen = sizeof s.Symbol.Name + sizeof s.Name;
    ok = SymFromAddr(hProcess, dwAddr, &Displacement, &s.Symbol);
    test_line(ok, "SymFromAddr(&%s)", szSymbolName);
    if (!ok) {
        test_diagnostic_last_error();
    } else {
        if (!g_bStripped) {
            ok = strcmp(s.Symbol.Name, szSymbolName) == 0;
        } else {
            // XXX: ignore differences due to demangling
            ok = strncmp(szSymbolName, s.Symbol.Name, strlen(szSymbolName)) == 0;
        }
        test_line(ok, "SymFromAddr(&%s).Name", szSymbolName);
        if (!ok) {
            test_diagnostic("Name = \"%s\" != \"%s\"",
                            s.Symbol.Name, szSymbolName);
        }
        ok = Displacement == dwExpectDisplacement;
        test_line(ok, "SymFromAddr(&%s).Displacement", szSymbolName);
        if (!ok) {
            test_diagnostic("Displacement = %I64x != %I64x",
                            Displacement, dwExpectDisplacement);
        }
    }
}

static void
checkSymLine(HANDLE hProcess,
             PVOID pvSymbol,
             const char *szSymbolName,
             const char *szFileName,
             DWORD dwLineNumber,
             DWORD64 dwExpectDisplacement)
{
    bool ok;

    DWORD64 dwAddr = (DWORD64)(UINT_PTR)pvSymbol;

    checkSym(hProcess, pvSymbol, szSymbolName, dwExpectDisplacement);

    if (g_bStripped) {
        // Don't check line nos
        return;
    }

    // Test SymGetLineFromAddr64
    DWORD dwDisplacement;
    IMAGEHLP_LINE64 Line;
    ZeroMemory(&Line, sizeof Line);
    Line.SizeOfStruct = sizeof Line;
    ok = SymGetLineFromAddr64(hProcess, dwAddr, &dwDisplacement, &Line);
    test_line(ok, "SymGetLineFromAddr64(&%s)", szSymbolName);
    if (!ok) {
        test_diagnostic_last_error();
    } else {
        ok = comparePath(Line.FileName, szFileName);
        test_line(ok, "SymGetLineFromAddr64(&%s).FileName", szSymbolName);
        if (!ok) {
            test_diagnostic("FileName = \"%s\" != \"%s\"",
                            Line.FileName, szFileName);
        }
        ok = Line.LineNumber == dwLineNumber;
        test_line(ok, "SymGetLineFromAddr64(&%s).LineNumber", szSymbolName);
        if (Line.LineNumber != dwLineNumber) {
            test_diagnostic("LineNumber = %lu != %lu",
                            Line.LineNumber, dwLineNumber);
        }
        ok = dwDisplacement == dwExpectDisplacement;
        test_line(ok, "SymGetLineFromAddr64(&%s).Displacement", szSymbolName);
        if (!ok) {
            test_diagnostic("Displacement = %lx != %I64x",
                            dwDisplacement, dwExpectDisplacement);
        }
    }
}

static void
    __attribute__ ((noinline))
checkCaller(HANDLE hProcess,
            PVOID pvCaller,
            const char *szSymbolName,
            const char *szFileName,
            DWORD dwLineNumber)
{
    void *addr = __builtin_return_address(0);
    DWORD64 displacement = (DWORD64)addr - (DWORD64)pvCaller;
    checkSymLine(hProcess, addr, szSymbolName, szFileName, dwLineNumber, displacement);
}

static void
checkExport(HANDLE hProcess,
            const char *szModuleName,
            const char *szSymbolName)
{
    HMODULE hModule = GetModuleHandleA(szModuleName);
    const PVOID pvSymbol = (PVOID)GetProcAddress(hModule, szSymbolName);
    checkSym(hProcess, pvSymbol, szSymbolName, 0);
}

static const DWORD foo_line = __LINE__; static int foo(int a, int b) {
    return a * b;
}

#define LINE_BARRIER rand();

int
main(int argc, char **argv)
{
    HANDLE hProcess = GetCurrentProcess();
    bool ok;

    if (strstr(argv[0], "test_mgwhelp_stripped")) {
        g_bStripped = TRUE;
    }

    HMODULE hMgwHelpDll = GetModuleHandleA("mgwhelp.dll");
    if (!hMgwHelpDll) {
        test_line(false, "GetModuleHandleA(\"mgwhelp.dll\")");
    } else {
        test_line(GetProcAddress(hMgwHelpDll, "SymGetOptions") != NULL, "GetProcAddress(\"SymGetOptions\")");
        test_line(GetProcAddress(hMgwHelpDll, "SymGetOptions@0") == NULL, "!GetProcAddress(\"SymGetOptions\")");
    }

    ok = SymInitialize(hProcess, "", TRUE);
    test_line(ok, "SymInitialize()");
    if (!ok) {
        test_diagnostic_last_error();
    } {
        checkSymLine(hProcess, (PVOID)&foo, "foo", __FILE__, foo_line, 0);

        checkCaller(hProcess, (PVOID)&main, "main", __FILE__, __LINE__); LINE_BARRIER

        // Test DbgHelp fallback
        // XXX: Doesn't work reliably on Wine
        if (!insideWine()) {
            checkExport(hProcess, "kernel32", "Sleep");
        }

        ok = SymCleanup(hProcess);
        test_line(ok, "SymCleanup()");
        if (!ok) {
            test_diagnostic_last_error();
        }
    }

    test_exit();
}
<|endoftext|>


<commit_before>#pragma once

#include <RenHook/ExecutableMeta/ExecutableMeta.hpp>
#include <RenHook/Hooks/Hook.hpp>
#include <RenHook/Pattern/Pattern.hpp>

namespace RenHook::Managers::Hooks
{
    namespace Private
    {
        std::shared_ptr<Hook> Create(const uintptr_t Address, const uintptr_t Detour, const std::string& Key);

        extern uintptr_t ImageBase;

        extern std::map<std::string, std::shared_ptr<RenHook::Hook>> Hooks;
    }

    template<typename T>
    std::shared_ptr<Hook> Create(uintptr_t Address, const T Detour, bool IsInIDARange, std::string Key)
    {
        if (Key.empty() == true)
        {
            Key = std::to_string(Address);
        }

        // Check if we already have a hooked function with that key.
        if (Private::Hooks.find(Key) != Private::Hooks.end())
        {
            return Private::Hooks.at(Key);
        }

        if (IsInIDARange == true)
        {
            Address = Address - Private::ImageBase + RenHook::ExecutableMeta::GetBaseAddress();
        }

        return Private::Create(Address, reinterpret_cast<uintptr_t>(Detour), Key);
    }

    template<typename T>
    std::shared_ptr<Hook> Create(const std::string& Module, const std::string& Function, const T Detour, std::string Key)
    {
        if (Key.empty() == true)
        {
            Key = Module + "::" + Function;
        }

        // Check if we already have a hooked function with that key.
        if (Private::Hooks.find(Key) != Private::Hooks.end())
        {
            return Private::Hooks.at(Key);
        }

        auto Handle = GetModuleHandleA(Module.c_str());

        // If we don't have the module loaded, try to load it.
        if (Handle == nullptr)
        {
            LoadLibraryA(Module.c_str());

            // Try again to get the module's handle.
            Handle = GetModuleHandleA(Module.c_str());

            // Is it loaded now?
            if (Handle == nullptr)
            {
                throw std::invalid_argument("Module not found");
            }
        }

        auto Address = GetProcAddress(Handle, Function.c_str());

        // Do we have an invalid address?
        if (Address == nullptr)
        {
            throw std::invalid_argument("Function not found in module");
        }

        return Private::Create(reinterpret_cast<uintptr_t>(Address), reinterpret_cast<uintptr_t>(Detour), Key);;
    }

    template<typename T>
    std::shared_ptr<Hook> Create(std::string Pattern, const T Detour, std::string Key)
    {
        if (Key.empty() == true)
        {
            Key = Pattern;
        }

        // Remove whitespaces between bytes.
        Pattern.erase(std::remove_if(Pattern.begin(), Pattern.end(), ::isspace), Pattern.end());

        // Make sure the pattern is properly aligned.
        if (Pattern.length() % 2 > 0)
        {
            throw std::invalid_argument("Pattern is not properly aligned");
        }

        // Check if we already have a hooked function with that pattern.
        if (Private::Hooks.find(Key) != Private::Hooks.end())
        {
            return Private::Hooks.at(Key);
        }

        auto Address = RenHook::Pattern(Pattern).Except(1).Get(1).To<uintptr_t>();

        if (Address == 0)
        {
            throw std::runtime_error("Pattern not found");
        }

        return Private::Create(Address, reinterpret_cast<uintptr_t>(Detour), Key);;
    }

    std::shared_ptr<Hook> Get(const uintptr_t Address);

    std::shared_ptr<Hook> Get(const std::string& Key);

    std::shared_ptr<Hook> Get(const std::string& Module, const std::string& Function);

    void Remove(const uintptr_t Address);

    void Remove(const std::string& Key);

    void Remove(const std::string& Module, const std::string& Function);

    void RemoveAll();
}<commit_msg>Change "Except" to "Expect"<commit_after>#pragma once

#include <RenHook/ExecutableMeta/ExecutableMeta.hpp>
#include <RenHook/Hooks/Hook.hpp>
#include <RenHook/Pattern/Pattern.hpp>

namespace RenHook::Managers::Hooks
{
    namespace Private
    {
        std::shared_ptr<Hook> Create(const uintptr_t Address, const uintptr_t Detour, const std::string& Key);

        extern uintptr_t ImageBase;

        extern std::map<std::string, std::shared_ptr<RenHook::Hook>> Hooks;
    }

    template<typename T>
    std::shared_ptr<Hook> Create(uintptr_t Address, const T Detour, bool IsInIDARange, std::string Key)
    {
        if (Key.empty() == true)
        {
            Key = std::to_string(Address);
        }

        // Check if we already have a hooked function with that key.
        if (Private::Hooks.find(Key) != Private::Hooks.end())
        {
            return Private::Hooks.at(Key);
        }

        if (IsInIDARange == true)
        {
            Address = Address - Private::ImageBase + RenHook::ExecutableMeta::GetBaseAddress();
        }

        return Private::Create(Address, reinterpret_cast<uintptr_t>(Detour), Key);
    }

    template<typename T>
    std::shared_ptr<Hook> Create(const std::string& Module, const std::string& Function, const T Detour, std::string Key)
    {
        if (Key.empty() == true)
        {
            Key = Module + "::" + Function;
        }

        // Check if we already have a hooked function with that key.
        if (Private::Hooks.find(Key) != Private::Hooks.end())
        {
            return Private::Hooks.at(Key);
        }

        auto Handle = GetModuleHandleA(Module.c_str());

        // If we don't have the module loaded, try to load it.
        if (Handle == nullptr)
        {
            LoadLibraryA(Module.c_str());

            // Try again to get the module's handle.
            Handle = GetModuleHandleA(Module.c_str());

            // Is it loaded now?
            if (Handle == nullptr)
            {
                throw std::invalid_argument("Module not found");
            }
        }

        auto Address = GetProcAddress(Handle, Function.c_str());

        // Do we have an invalid address?
        if (Address == nullptr)
        {
            throw std::invalid_argument("Function not found in module");
        }

        return Private::Create(reinterpret_cast<uintptr_t>(Address), reinterpret_cast<uintptr_t>(Detour), Key);;
    }

    template<typename T>
    std::shared_ptr<Hook> Create(std::string Pattern, const T Detour, std::string Key)
    {
        if (Key.empty() == true)
        {
            Key = Pattern;
        }

        // Remove whitespaces between bytes.
        Pattern.erase(std::remove_if(Pattern.begin(), Pattern.end(), ::isspace), Pattern.end());

        // Make sure the pattern is properly aligned.
        if (Pattern.length() % 2 > 0)
        {
            throw std::invalid_argument("Pattern is not properly aligned");
        }

        // Check if we already have a hooked function with that pattern.
        if (Private::Hooks.find(Key) != Private::Hooks.end())
        {
            return Private::Hooks.at(Key);
        }

        auto Address = RenHook::Pattern(Pattern).Expect(1).Get(1).To<uintptr_t>();

        if (Address == 0)
        {
            throw std::runtime_error("Pattern not found");
        }

        return Private::Create(Address, reinterpret_cast<uintptr_t>(Detour), Key);;
    }

    std::shared_ptr<Hook> Get(const uintptr_t Address);

    std::shared_ptr<Hook> Get(const std::string& Key);

    std::shared_ptr<Hook> Get(const std::string& Module, const std::string& Function);

    void Remove(const uintptr_t Address);

    void Remove(const std::string& Key);

    void Remove(const std::string& Module, const std::string& Function);

    void RemoveAll();
}<|endoftext|>


<commit_before>// Unit test includes
#include "libmesh_cppunit.h"
#include "test_comm.h"

// libMesh includes
#include <libmesh/libmesh.h>
#include <libmesh/xdr_cxx.h>
#include <libmesh/int_range.h>
#include <timpi/communicator.h>

// C++ includes
#include <vector>

using namespace libMesh;

class XdrTest : public CppUnit::TestCase {
public:
  CPPUNIT_TEST_SUITE( XdrTest );

  CPPUNIT_TEST( testDataVec );
  CPPUNIT_TEST( testDataStream );

  CPPUNIT_TEST_SUITE_END();

private:

public:
  void setUp()
  {}

  void tearDown()
  {}

  void testDataVec ()
  {
    std::vector<Real> vec = {libMesh::pi, 2*libMesh::pi, 3*libMesh::pi};

    // Test reading/writing on 1 processor
    if (TestCommWorld->rank() == 0)
      {
        // Write to file
        {
          Xdr xdr("output.dat", WRITE);
          xdr.data(vec, "# This is a comment");
        }

        // Read from file
        {
          Xdr xdr("output.dat", READ);
          std::vector<Real> vec_in;
          xdr.data(vec_in);

          // Check that correct number of values were read in
          CPPUNIT_ASSERT_EQUAL(vec_in.size(), vec.size());

          // Check that values were written/read with sufficient accuracy
          for (auto i : index_range(vec_in))
            LIBMESH_ASSERT_FP_EQUAL(vec[i], vec_in[i], TOLERANCE);
        }
      }
  }

  void testDataStream ()
  {
    std::vector<Real> vec(100);
    for (auto i : index_range(vec))
      vec[i] = static_cast<Real>(i+1) / vec.size();

    // Test reading/writing on 1 processor
    if (TestCommWorld->rank() == 0)
      {
        // Write to file. If "line_break" does not exactly divide the
        // vector size, there will be one line with fewer values than
        // the others.
        {
          Xdr xdr("output.dat", WRITE);
          xdr.data_stream(vec.data(), vec.size(), /*line_break=*/16);
        }

        // Read from file. To use data_stream(), the storage needs to
        // be pre-sized and the line_break parameter is ignored.
        {
          Xdr xdr("output.dat", READ);
          std::vector<Real> vec_in(100);
          xdr.data_stream(vec_in.data(), vec_in.size());

          // Check that values were written/read correctly
          for (auto i : index_range(vec_in))
            LIBMESH_ASSERT_FP_EQUAL(vec[i], vec_in[i], TOLERANCE);
        }
      }
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION( XdrTest );
<commit_msg>Ensure Xdr test isn't set up for a race condition<commit_after>// Unit test includes
#include "libmesh_cppunit.h"
#include "test_comm.h"

// libMesh includes
#include <libmesh/libmesh.h>
#include <libmesh/xdr_cxx.h>
#include <libmesh/int_range.h>
#include <timpi/communicator.h>

// C++ includes
#include <vector>

using namespace libMesh;

class XdrTest : public CppUnit::TestCase {
public:
  CPPUNIT_TEST_SUITE( XdrTest );

  CPPUNIT_TEST( testDataVec );
  CPPUNIT_TEST( testDataStream );

  CPPUNIT_TEST_SUITE_END();

private:

public:
  void setUp()
  {}

  void tearDown()
  {}

  void testDataVec ()
  {
    std::vector<Real> vec = {libMesh::pi, 2*libMesh::pi, 3*libMesh::pi};

    // There was once a weird bug mutating our TestCommWorld in
    // a previous unit test, which turned *this* test into a race
    // condition.  Let's make sure that never happens again.
    CPPUNIT_ASSERT_EQUAL(TestCommWorld->rank(),
                         libMesh::global_processor_id());

    // Test reading/writing on 1 processor
    if (TestCommWorld->rank() == 0)
      {
        // Write to file
        {
          Xdr xdr("output.dat", WRITE);
          xdr.data(vec, "# This is a comment");
        }

        // Read from file
        {
          Xdr xdr("output.dat", READ);
          std::vector<Real> vec_in;
          xdr.data(vec_in);

          // Check that correct number of values were read in
          CPPUNIT_ASSERT_EQUAL(vec_in.size(), vec.size());

          // Check that values were written/read with sufficient accuracy
          for (auto i : index_range(vec_in))
            LIBMESH_ASSERT_FP_EQUAL(vec[i], vec_in[i], TOLERANCE);
        }
      }
  }

  void testDataStream ()
  {
    std::vector<Real> vec(100);
    for (auto i : index_range(vec))
      vec[i] = static_cast<Real>(i+1) / vec.size();

    // Test reading/writing on 1 processor
    if (TestCommWorld->rank() == 0)
      {
        // Write to file. If "line_break" does not exactly divide the
        // vector size, there will be one line with fewer values than
        // the others.
        {
          Xdr xdr("output.dat", WRITE);
          xdr.data_stream(vec.data(), vec.size(), /*line_break=*/16);
        }

        // Read from file. To use data_stream(), the storage needs to
        // be pre-sized and the line_break parameter is ignored.
        {
          Xdr xdr("output.dat", READ);
          std::vector<Real> vec_in(100);
          xdr.data_stream(vec_in.data(), vec_in.size());

          // Check that values were written/read correctly
          for (auto i : index_range(vec_in))
            LIBMESH_ASSERT_FP_EQUAL(vec[i], vec_in[i], TOLERANCE);
        }
      }
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION( XdrTest );
<|endoftext|>