<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include "SlsRequestQueue.hxx"

#include <set>

namespace sd { namespace slidesorter { namespace cache {

/** This class extends the actual request data with additional information
    that is used by the priority queues.
*/
class Request
{
public:
    Request (
        CacheKey aKey, sal_Int32 nPriority, RequestPriorityClass eClass)
        : maKey(aKey), mnPriorityInClass(nPriority), meClass(eClass)
    {}
    /** Sort requests according to priority classes and then to priorities.
    */
    class Comparator { public:
        bool operator() (const Request& rRequest1, const Request& rRequest2)
        {
            if (rRequest1.meClass == rRequest2.meClass)
                return (rRequest1.mnPriorityInClass > rRequest2.mnPriorityInClass);
            else
                return (rRequest1.meClass < rRequest2.meClass);
        }
    };
    /** Request data is compared arbitrarily by their addresses in memory.
        This just establishes an order so that the STL containers are happy.
        The order is not semantically interpreted.
    */
    class DataComparator { public:
        DataComparator (const Request&rRequest):maKey(rRequest.maKey){}
        DataComparator (const CacheKey aKey):maKey(aKey){}
        bool operator() (const Request& rRequest) { return maKey == rRequest.maKey; }
    private: const CacheKey maKey;
    };

    CacheKey maKey;
    sal_Int32 mnPriorityInClass;
    RequestPriorityClass meClass;
};

class RequestQueue::Container
    : public ::std::set<
        Request,
        Request::Comparator>
{
};

//=====  GenericRequestQueue  =================================================

RequestQueue::RequestQueue (const SharedCacheContext& rpCacheContext)
    : maMutex(),
      mpRequestQueue(new Container()),
      mpCacheContext(rpCacheContext),
      mnMinimumPriority(0),
      mnMaximumPriority(1)
{
}

RequestQueue::~RequestQueue (void)
{
    Clear();
}

void RequestQueue::AddRequest (
    CacheKey aKey,
    RequestPriorityClass eRequestClass,
    bool /*bInsertWithHighestPriority*/)
{
    ::osl::MutexGuard aGuard (maMutex);

    OSL_ASSERT(eRequestClass>=MIN__CLASS && eRequestClass<=MAX__CLASS);

    // If the request is already a member of the queue then remove it so
    // that the following insertion will use the new prioritization.
#if OSL_DEBUG_LEVEL >=2
    bool bRemoved =
#endif
        RemoveRequest(aKey);

    // The priority of the request inside its priority class is defined by
    // the page number.  This ensures a strict top-to-bottom, left-to-right
    // order.
    sal_Int32 nPriority (mpCacheContext->GetPriority(aKey));
    Request aRequest (aKey, nPriority, eRequestClass);

    std::pair<Container::iterator,bool> ret = mpRequestQueue->insert(aRequest);
    bool bInserted = ret.second == true;

    if (bInserted)
    {
        SdrPage *pPage = const_cast<SdrPage*>(aRequest.maKey);
        pPage->AddPageUser(*this);
    }

    SSCD_SET_REQUEST_CLASS(aKey,eRequestClass);

#if OSL_DEBUG_LEVEL >=2
    SAL_INFO("sd.sls", OSL_THIS_FUNC << ": " << (bRemoved?"replaced":"added")
        << " request for page " << ((aKey->GetPageNum()-1)/2)
        << " with priority class " << static_cast<int>(eRequestClass));
#endif
}

void RequestQueue::PageInDestruction(const SdrPage& rPage)
{
    //remove any requests pending for this page which is going away now
    RemoveRequest(&rPage);
}

bool RequestQueue::RemoveRequest (
    CacheKey aKey)
{
    bool bRequestWasRemoved (false);
    ::osl::MutexGuard aGuard (maMutex);

    while(true)
    {
        Container::const_iterator aRequestIterator = ::std::find_if (
            mpRequestQueue->begin(),
            mpRequestQueue->end(),
            Request::DataComparator(aKey));
        if (aRequestIterator != mpRequestQueue->end())
        {
            if (aRequestIterator->mnPriorityInClass == mnMinimumPriority+1)
                mnMinimumPriority++;
            else if (aRequestIterator->mnPriorityInClass == mnMaximumPriority-1)
                mnMaximumPriority--;

            SdrPage *pPage = const_cast<SdrPage*>(aRequestIterator->maKey);
            pPage->RemovePageUser(*this);
            mpRequestQueue->erase(aRequestIterator);

            bRequestWasRemoved = true;

            if (bRequestWasRemoved)
            {
                SSCD_SET_STATUS(aKey,NONE);
            }
        }
        else
            break;
    }

    return bRequestWasRemoved;
}

void RequestQueue::ChangeClass (
    CacheKey aKey,
    RequestPriorityClass eNewRequestClass)
{
    ::osl::MutexGuard aGuard (maMutex);

    OSL_ASSERT(eNewRequestClass>=MIN__CLASS && eNewRequestClass<=MAX__CLASS);

    Container::const_iterator iRequest (
        ::std::find_if (
            mpRequestQueue->begin(),
            mpRequestQueue->end(),
            Request::DataComparator(aKey)));
    if (iRequest!=mpRequestQueue->end() && iRequest->meClass!=eNewRequestClass)
    {
        AddRequest(aKey, eNewRequestClass, true);
        SSCD_SET_REQUEST_CLASS(aKey,eNewRequestClass);
    }
}

CacheKey RequestQueue::GetFront (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    if (mpRequestQueue->empty())
        throw ::com::sun::star::uno::RuntimeException("RequestQueue::GetFront(): queue is empty",
            NULL);

    return mpRequestQueue->begin()->maKey;
}

RequestPriorityClass RequestQueue::GetFrontPriorityClass (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    if (mpRequestQueue->empty())
        throw ::com::sun::star::uno::RuntimeException("RequestQueue::GetFrontPriorityClass(): queue is empty",
            NULL);

    return mpRequestQueue->begin()->meClass;
}

void RequestQueue::PopFront (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    if ( ! mpRequestQueue->empty())
    {
        SSCD_SET_STATUS(maRequestQueue.begin()->mpData->GetPage(),NONE);

        Container::const_iterator aIter(mpRequestQueue->begin());
        SdrPage *pPage = const_cast<SdrPage*>(aIter->maKey);
        pPage->RemovePageUser(*this);
        mpRequestQueue->erase(aIter);

        // Reset the priority counter if possible.
        if (mpRequestQueue->empty())
        {
            mnMinimumPriority = 0;
            mnMaximumPriority = 1;
        }
    }
}

bool RequestQueue::IsEmpty (void)
{
    ::osl::MutexGuard aGuard (maMutex);
    return mpRequestQueue->empty();
}

void RequestQueue::Clear (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    for (Container::iterator aI = mpRequestQueue->begin(), aEnd = mpRequestQueue->end(); aI != aEnd; ++aI)
    {
        SdrPage *pPage = const_cast<SdrPage*>(aI->maKey);
        pPage->RemovePageUser(*this);
    }

    mpRequestQueue->clear();
    mnMinimumPriority = 0;
    mnMaximumPriority = 1;
}

::osl::Mutex& RequestQueue::GetMutex (void)
{
    return maMutex;
}

} } } // end of namespace ::sd::slidesorter::cache

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>remove unused ctor variant<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include "SlsRequestQueue.hxx"

#include <set>

namespace sd { namespace slidesorter { namespace cache {

/** This class extends the actual request data with additional information
    that is used by the priority queues.
*/
class Request
{
public:
    Request (
        CacheKey aKey, sal_Int32 nPriority, RequestPriorityClass eClass)
        : maKey(aKey), mnPriorityInClass(nPriority), meClass(eClass)
    {}
    /** Sort requests according to priority classes and then to priorities.
    */
    class Comparator { public:
        bool operator() (const Request& rRequest1, const Request& rRequest2)
        {
            if (rRequest1.meClass == rRequest2.meClass)
                return (rRequest1.mnPriorityInClass > rRequest2.mnPriorityInClass);
            else
                return (rRequest1.meClass < rRequest2.meClass);
        }
    };
    /** Request data is compared arbitrarily by their addresses in memory.
        This just establishes an order so that the STL containers are happy.
        The order is not semantically interpreted.
    */
    class DataComparator
    {
    public:
        DataComparator (const CacheKey aKey)
            : maKey(aKey)
        {
        }
        bool operator() (const Request& rRequest) const
        {
            return maKey == rRequest.maKey;
        }
    private:
        const CacheKey maKey;
    };

    CacheKey maKey;
    sal_Int32 mnPriorityInClass;
    RequestPriorityClass meClass;
};

class RequestQueue::Container
    : public ::std::set<
        Request,
        Request::Comparator>
{
};

//=====  GenericRequestQueue  =================================================

RequestQueue::RequestQueue (const SharedCacheContext& rpCacheContext)
    : maMutex(),
      mpRequestQueue(new Container()),
      mpCacheContext(rpCacheContext),
      mnMinimumPriority(0),
      mnMaximumPriority(1)
{
}

RequestQueue::~RequestQueue (void)
{
    Clear();
}

void RequestQueue::AddRequest (
    CacheKey aKey,
    RequestPriorityClass eRequestClass,
    bool /*bInsertWithHighestPriority*/)
{
    ::osl::MutexGuard aGuard (maMutex);

    OSL_ASSERT(eRequestClass>=MIN__CLASS && eRequestClass<=MAX__CLASS);

    // If the request is already a member of the queue then remove it so
    // that the following insertion will use the new prioritization.
#if OSL_DEBUG_LEVEL >=2
    bool bRemoved =
#endif
        RemoveRequest(aKey);

    // The priority of the request inside its priority class is defined by
    // the page number.  This ensures a strict top-to-bottom, left-to-right
    // order.
    sal_Int32 nPriority (mpCacheContext->GetPriority(aKey));
    Request aRequest (aKey, nPriority, eRequestClass);

    std::pair<Container::iterator,bool> ret = mpRequestQueue->insert(aRequest);
    bool bInserted = ret.second == true;

    if (bInserted)
    {
        SdrPage *pPage = const_cast<SdrPage*>(aRequest.maKey);
        pPage->AddPageUser(*this);
    }

    SSCD_SET_REQUEST_CLASS(aKey,eRequestClass);

#if OSL_DEBUG_LEVEL >=2
    SAL_INFO("sd.sls", OSL_THIS_FUNC << ": " << (bRemoved?"replaced":"added")
        << " request for page " << ((aKey->GetPageNum()-1)/2)
        << " with priority class " << static_cast<int>(eRequestClass));
#endif
}

void RequestQueue::PageInDestruction(const SdrPage& rPage)
{
    //remove any requests pending for this page which is going away now
    RemoveRequest(&rPage);
}

bool RequestQueue::RemoveRequest (
    CacheKey aKey)
{
    bool bRequestWasRemoved (false);
    ::osl::MutexGuard aGuard (maMutex);

    while(true)
    {
        Container::const_iterator aRequestIterator = ::std::find_if (
            mpRequestQueue->begin(),
            mpRequestQueue->end(),
            Request::DataComparator(aKey));
        if (aRequestIterator != mpRequestQueue->end())
        {
            if (aRequestIterator->mnPriorityInClass == mnMinimumPriority+1)
                mnMinimumPriority++;
            else if (aRequestIterator->mnPriorityInClass == mnMaximumPriority-1)
                mnMaximumPriority--;

            SdrPage *pPage = const_cast<SdrPage*>(aRequestIterator->maKey);
            pPage->RemovePageUser(*this);
            mpRequestQueue->erase(aRequestIterator);

            bRequestWasRemoved = true;

            if (bRequestWasRemoved)
            {
                SSCD_SET_STATUS(aKey,NONE);
            }
        }
        else
            break;
    }

    return bRequestWasRemoved;
}

void RequestQueue::ChangeClass (
    CacheKey aKey,
    RequestPriorityClass eNewRequestClass)
{
    ::osl::MutexGuard aGuard (maMutex);

    OSL_ASSERT(eNewRequestClass>=MIN__CLASS && eNewRequestClass<=MAX__CLASS);

    Container::const_iterator iRequest (
        ::std::find_if (
            mpRequestQueue->begin(),
            mpRequestQueue->end(),
            Request::DataComparator(aKey)));
    if (iRequest!=mpRequestQueue->end() && iRequest->meClass!=eNewRequestClass)
    {
        AddRequest(aKey, eNewRequestClass, true);
        SSCD_SET_REQUEST_CLASS(aKey,eNewRequestClass);
    }
}

CacheKey RequestQueue::GetFront (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    if (mpRequestQueue->empty())
        throw ::com::sun::star::uno::RuntimeException("RequestQueue::GetFront(): queue is empty",
            NULL);

    return mpRequestQueue->begin()->maKey;
}

RequestPriorityClass RequestQueue::GetFrontPriorityClass (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    if (mpRequestQueue->empty())
        throw ::com::sun::star::uno::RuntimeException("RequestQueue::GetFrontPriorityClass(): queue is empty",
            NULL);

    return mpRequestQueue->begin()->meClass;
}

void RequestQueue::PopFront (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    if ( ! mpRequestQueue->empty())
    {
        SSCD_SET_STATUS(maRequestQueue.begin()->mpData->GetPage(),NONE);

        Container::const_iterator aIter(mpRequestQueue->begin());
        SdrPage *pPage = const_cast<SdrPage*>(aIter->maKey);
        pPage->RemovePageUser(*this);
        mpRequestQueue->erase(aIter);

        // Reset the priority counter if possible.
        if (mpRequestQueue->empty())
        {
            mnMinimumPriority = 0;
            mnMaximumPriority = 1;
        }
    }
}

bool RequestQueue::IsEmpty (void)
{
    ::osl::MutexGuard aGuard (maMutex);
    return mpRequestQueue->empty();
}

void RequestQueue::Clear (void)
{
    ::osl::MutexGuard aGuard (maMutex);

    for (Container::iterator aI = mpRequestQueue->begin(), aEnd = mpRequestQueue->end(); aI != aEnd; ++aI)
    {
        SdrPage *pPage = const_cast<SdrPage*>(aI->maKey);
        pPage->RemovePageUser(*this);
    }

    mpRequestQueue->clear();
    mnMinimumPriority = 0;
    mnMaximumPriority = 1;
}

::osl::Mutex& RequestQueue::GetMutex (void)
{
    return maMutex;
}

} } } // end of namespace ::sd::slidesorter::cache

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                       OpenSim:  FixedFrame.cpp                             *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2012 Stanford University and the Authors                *
 * Author(s): Matt DeMers & Ayman Habib                                       *
 *                                                                            *
 * 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.                                             *
 * -------------------------------------------------------------------------- */

//=============================================================================
// INCLUDES
//=============================================================================
#include "FixedFrame.h"
#include <OpenSim/Simulation/Model/Model.h>

//=============================================================================
// STATICS
//=============================================================================
using namespace std;
//using namespace SimTK;
using namespace OpenSim;
using SimTK::Mat33;
using SimTK::Vec3;

//=============================================================================
// CONSTRUCTOR(S)
//=============================================================================
//_____________________________________________________________________________
/**
 * Default constructor.
 */
FixedFrame::FixedFrame() : RigidFrame()
{
    setNull();
    constructInfrastructure();
}

//_____________________________________________________________________________
/**
 * Constructors.
 */
FixedFrame::FixedFrame(const RigidFrame& parent_frame) : RigidFrame()
{
    setNull();
    constructInfrastructure();
    setParentFrame(parent_frame);

}

FixedFrame::FixedFrame(const RigidFrame& parent_frame, const SimTK::Transform&
        xform) : RigidFrame()
{
    setNull();
    constructInfrastructure();
    setParentFrame(parent_frame);
    setTransform(xform);

}
//_____________________________________________________________________________
/**
* Set a null frame as Identity rotation, 0 translation
*/
void FixedFrame::setNull()
{
    _isCacheInitialized = false;
    _transform.setToZero();
    _mbTransform.setToZero();
    setAuthors("Matt DeMers");
}
//_____________________________________________________________________________
/**
* construct properties
*/

void FixedFrame::constructProperties()
{
    SimTK::Vec3 zero(0.0, 0.0, 0.0);
    constructProperty_translation(zero);
    constructProperty_orientation(zero);
    // transform at default
}

void FixedFrame::constructConnectors()
{
    constructConnector<RigidFrame>("parent_frame");
}

void FixedFrame::addToSystem(SimTK::MultibodySystem& system) const
{
    // Traverse the tree of consecutive FixedFrame connections to determine
    // this FixedFrame's root segment (Body/MobilizedBody).  We store that
    // information instead of recomputing it on the fly when asked for information
    // about our connection to a root segment.

    initFixedFrameCache();

}
//=============================================================================
// FRAME COMPUTATIONS
//=============================================================================
//_____________________________________________________________________________
const SimTK::Transform& FixedFrame::getTransform() const
{
    // If properties have been updated, then update the cached transform object
    // to be in sync.
    _transform.updP() = get_translation();
    _transform.updR().setRotationToBodyFixedXYZ(get_orientation());
    return _transform;
}
void FixedFrame::setTransform(const SimTK::Transform& xform)
{
    _transform = xform;
    // Make sure properties are updated in case we either call gettters or
    // serialize after this call
    set_translation(xform.p());
    set_orientation(xform.R().convertRotationToBodyFixedXYZ());
    invalidate();

}

void FixedFrame::invalidate() const
{
    _isCacheInitialized = false;
    _mbTransform.setToNaN();
    if (!_model.empty())
    {
        _model->invalidateSystem();
    }
}

bool FixedFrame::isPathToBaseValid() const
{
    //  check if I'm valid first
    if (_isCacheInitialized == 0) { return false; }

    // check if my parent is another FixedFrame
    const FixedFrame* parent = dynamic_cast<const FixedFrame*>(&getParentFrame());
    if (parent != 0)
    {
        // check if my parent FixedFrame is valid
        return parent->isPathToBaseValid();
    }
    // otherwise, I'm valid and my parent is a base segment
    return true;

}

void FixedFrame::initFixedFrameCache() const
{
    const RigidFrame& parent = getParentFrame();
    const OpenSim::FixedFrame* parentFixedFrame =
        +dynamic_cast<const OpenSim::FixedFrame *>(&parent);
    if (parentFixedFrame != 0)
    {
        // The parent frame is another FixedFrame
        // The parent FixedFrame must resolve its hierarchy before we ask
        // for its root MobilizedBodyIndex.
        // check if the FixedFrame has populated its root segments
        if (parentFixedFrame->isPathToBaseValid() == 0)
        {
            parentFixedFrame->initFixedFrameCache();
        }
        // all variables pointing to the parent's root MobilizedBody should be valid
        // X_BF = X_BP*X_PF
        _mbTransform = parentFixedFrame->getTransformInMobilizedBody()*getTransform();
    }
    else
    {
        // if I'm not on a FixedFrame, I'm on a Body or other root RigidFrame.
        // Therefore, my root transform is the same as my local transform
        _mbTransform = getTransform();
    }

    // Ask my parent RigidFrame which root Body/MobilizedBody I'm attached to

    _index = parent.getMobilizedBodyIndex();

    _isCacheInitialized = true;
}
//=============================================================================
// GET AND SET
//=============================================================================
//_____________________________________________________________________________
void FixedFrame::setParentFrame(const RigidFrame& parent_frame)
{
    updConnector<RigidFrame>("parent_frame").connect(parent_frame);
    invalidate();
}
const RigidFrame& FixedFrame::getParentFrame() const
{
    return getConnector<RigidFrame>("parent_frame").getConnectee();
}

//=============================================================================
// SCALING
//=============================================================================
//_____________________________________________________________________________

//=============================================================================
// UTILITY
//=============================================================================

//=============================================================================
// I/O
//=============================================================================

<commit_msg>Removed "+" typo and fixed comparison statement in FixedFrame implementation.<commit_after>/* -------------------------------------------------------------------------- *
 *                       OpenSim:  FixedFrame.cpp                             *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2012 Stanford University and the Authors                *
 * Author(s): Matt DeMers & Ayman Habib                                       *
 *                                                                            *
 * 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.                                             *
 * -------------------------------------------------------------------------- */

//=============================================================================
// INCLUDES
//=============================================================================
#include "FixedFrame.h"
#include <OpenSim/Simulation/Model/Model.h>

//=============================================================================
// STATICS
//=============================================================================
using namespace std;
//using namespace SimTK;
using namespace OpenSim;
using SimTK::Mat33;
using SimTK::Vec3;

//=============================================================================
// CONSTRUCTOR(S)
//=============================================================================
//_____________________________________________________________________________
/**
 * Default constructor.
 */
FixedFrame::FixedFrame() : RigidFrame()
{
    setNull();
    constructInfrastructure();
}

//_____________________________________________________________________________
/**
 * Constructors.
 */
FixedFrame::FixedFrame(const RigidFrame& parent_frame) : RigidFrame()
{
    setNull();
    constructInfrastructure();
    setParentFrame(parent_frame);

}

FixedFrame::FixedFrame(const RigidFrame& parent_frame, const SimTK::Transform&
        xform) : RigidFrame()
{
    setNull();
    constructInfrastructure();
    setParentFrame(parent_frame);
    setTransform(xform);

}
//_____________________________________________________________________________
/**
* Set a null frame as Identity rotation, 0 translation
*/
void FixedFrame::setNull()
{
    _isCacheInitialized = false;
    _transform.setToZero();
    _mbTransform.setToZero();
    setAuthors("Matt DeMers");
}
//_____________________________________________________________________________
/**
* construct properties
*/

void FixedFrame::constructProperties()
{
    SimTK::Vec3 zero(0.0, 0.0, 0.0);
    constructProperty_translation(zero);
    constructProperty_orientation(zero);
    // transform at default
}

void FixedFrame::constructConnectors()
{
    constructConnector<RigidFrame>("parent_frame");
}

void FixedFrame::addToSystem(SimTK::MultibodySystem& system) const
{
    // Traverse the tree of consecutive FixedFrame connections to determine
    // this FixedFrame's root segment (Body/MobilizedBody).  We store that
    // information instead of recomputing it on the fly when asked for information
    // about our connection to a root segment.

    initFixedFrameCache();

}
//=============================================================================
// FRAME COMPUTATIONS
//=============================================================================
//_____________________________________________________________________________
const SimTK::Transform& FixedFrame::getTransform() const
{
    // If properties have been updated, then update the cached transform object
    // to be in sync.
    _transform.updP() = get_translation();
    _transform.updR().setRotationToBodyFixedXYZ(get_orientation());
    return _transform;
}
void FixedFrame::setTransform(const SimTK::Transform& xform)
{
    _transform = xform;
    // Make sure properties are updated in case we either call gettters or
    // serialize after this call
    set_translation(xform.p());
    set_orientation(xform.R().convertRotationToBodyFixedXYZ());
    invalidate();

}

void FixedFrame::invalidate() const
{
    _isCacheInitialized = false;
    _mbTransform.setToNaN();
    if (!_model.empty())
    {
        _model->invalidateSystem();
    }
}

bool FixedFrame::isPathToBaseValid() const
{
    //  check if I'm valid first
    if (_isCacheInitialized == 0) { return false; }

    // check if my parent is another FixedFrame
    const FixedFrame* parent = dynamic_cast<const FixedFrame*>(&getParentFrame());
    if (parent != 0)
    {
        // check if my parent FixedFrame is valid
        return parent->isPathToBaseValid();
    }
    // otherwise, I'm valid and my parent is a base segment
    return true;

}

void FixedFrame::initFixedFrameCache() const
{
    const RigidFrame& parent = getParentFrame();
    const OpenSim::FixedFrame* parentFixedFrame =
        dynamic_cast<const OpenSim::FixedFrame *>(&parent);
    if (parentFixedFrame != 0)
    {
        // The parent frame is another FixedFrame
        // The parent FixedFrame must resolve its hierarchy before we ask
        // for its root MobilizedBodyIndex.
        // check if the FixedFrame has populated its root segments
        if (!parentFixedFrame->isPathToBaseValid())
        {
            parentFixedFrame->initFixedFrameCache();
        }
        // all variables pointing to the parent's root MobilizedBody should be valid
        // X_BF = X_BP*X_PF
        _mbTransform = parentFixedFrame->getTransformInMobilizedBody()*getTransform();
    }
    else
    {
        // if I'm not on a FixedFrame, I'm on a Body or other root RigidFrame.
        // Therefore, my root transform is the same as my local transform
        _mbTransform = getTransform();
    }

    // Ask my parent RigidFrame which root Body/MobilizedBody I'm attached to

    _index = parent.getMobilizedBodyIndex();

    _isCacheInitialized = true;
}
//=============================================================================
// GET AND SET
//=============================================================================
//_____________________________________________________________________________
void FixedFrame::setParentFrame(const RigidFrame& parent_frame)
{
    updConnector<RigidFrame>("parent_frame").connect(parent_frame);
    invalidate();
}
const RigidFrame& FixedFrame::getParentFrame() const
{
    return getConnector<RigidFrame>("parent_frame").getConnectee();
}

//=============================================================================
// SCALING
//=============================================================================
//_____________________________________________________________________________

//=============================================================================
// UTILITY
//=============================================================================

//=============================================================================
// I/O
//=============================================================================

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/http_connection.hpp"

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <asio/ip/tcp.hpp>
#include <string>

using boost::bind;

namespace libtorrent
{

void http_connection::get(std::string const& url, time_duration timeout)
{
	std::string protocol;
	std::string hostname;
	std::string path;
	int port;
	boost::tie(protocol, hostname, port, path) = parse_url_components(url);
	std::stringstream headers;
	headers << "GET " << path << " HTTP/1.0\r\n"
		"Host:" << hostname <<
		"Connection: close\r\n"
		"\r\n\r\n";
	sendbuffer = headers.str();
	start(hostname, boost::lexical_cast<std::string>(port), timeout);
}

void http_connection::start(std::string const& hostname, std::string const& port
	, time_duration timeout)
{
	m_timeout = timeout;
	m_timer.expires_from_now(m_timeout);
	m_timer.async_wait(bind(&http_connection::on_timeout
		, boost::weak_ptr<http_connection>(shared_from_this()), _1));
	m_called = false;
	if (m_sock.is_open() && m_hostname == hostname && m_port == port)
	{
		m_parser.reset();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
	else
	{
		m_sock.close();
		tcp::resolver::query query(hostname, port);
		m_resolver.async_resolve(query, bind(&http_connection::on_resolve
			, shared_from_this(), _1, _2));
		m_hostname = hostname;
		m_port = port;
	}
}

void http_connection::on_timeout(boost::weak_ptr<http_connection> p
	, asio::error_code const& e)
{
	if (e == asio::error::operation_aborted) return;
	boost::shared_ptr<http_connection> c = p.lock();
	if (!c) return;
	if (c->m_bottled && c->m_called) return;

	if (c->m_last_receive + c->m_timeout < time_now())
	{
		c->m_called = true;
		c->m_handler(asio::error::timed_out, c->m_parser, 0, 0);
		return;
	}

	c->m_timer.expires_at(c->m_last_receive + c->m_timeout);
	c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
}

void http_connection::close()
{
	m_timer.cancel();
	m_limiter_timer.cancel();
	m_sock.close();
	m_hostname.clear();
	m_port.clear();
}

void http_connection::on_resolve(asio::error_code const& e
		, tcp::resolver::iterator i)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}
	assert(i != tcp::resolver::iterator());
	m_sock.async_connect(*i, boost::bind(&http_connection::on_connect
		, shared_from_this(), _1/*, ++i*/));
}

void http_connection::on_connect(asio::error_code const& e
	/*, tcp::resolver::iterator i*/)
{
	if (!e)
	{
		m_last_receive = time_now();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
/*	else if (i != tcp::resolver::iterator())
	{
		// The connection failed. Try the next endpoint in the list.
		m_sock.close();
		m_sock.async_connect(*i, bind(&http_connection::on_connect
			, shared_from_this(), _1, ++i));
	}
*/	else
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
	}
}

void http_connection::on_write(asio::error_code const& e)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	std::string().swap(sendbuffer);
	m_recvbuffer.resize(4096);

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_read(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	if (m_rate_limit)
	{
		m_download_quota -= bytes_transferred;
		assert(m_download_quota >= 0);
	}

	if (e == asio::error::eof)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(asio::error_code(), m_parser, 0, 0);
		return;
	}

	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	m_read_pos += bytes_transferred;
	assert(m_read_pos <= int(m_recvbuffer.size()));

	if (m_bottled || !m_parser.header_finished())
	{
		libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
			, &m_recvbuffer[0] + m_read_pos);
		m_parser.incoming(rcv_buf);
		if (!m_bottled && m_parser.header_finished())
		{
			if (m_read_pos > m_parser.body_start())
				m_handler(e, m_parser, &m_recvbuffer[0] + m_parser.body_start()
					, m_read_pos - m_parser.body_start());
			m_read_pos = 0;
			m_last_receive = time_now();
		}
		else if (m_bottled && m_parser.finished())
		{
			m_timer.cancel();
			if (m_bottled && m_called) return;
			m_called = true;
			m_handler(e, m_parser, 0, 0);
		}
	}
	else
	{
		assert(!m_bottled);
		m_handler(e, m_parser, &m_recvbuffer[0], m_read_pos);
		m_read_pos = 0;
		m_last_receive = time_now();
	}

	if (int(m_recvbuffer.size()) == m_read_pos)
		m_recvbuffer.resize((std::min)(m_read_pos + 2048, 1024*500));
	if (m_read_pos == 1024 * 500)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(asio::error::eof, m_parser, 0, 0);
		return;
	}
	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_assign_bandwidth(asio::error_code const& e)
{
	if ((e == asio::error::operation_aborted
		&& m_limiter_timer_active)
		|| !m_sock.is_open())
	{
		if (!m_bottled || !m_called)
			m_handler(e, m_parser, 0, 0);
	}
	m_limiter_timer_active = false;
	if (e) return;

	if (m_download_quota > 0) return;

	m_download_quota = m_rate_limit / 4;

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (amount_to_read > m_download_quota)
		amount_to_read = m_download_quota;

	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));

	m_limiter_timer_active = true;
	m_limiter_timer.expires_from_now(milliseconds(250));
	m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
		, shared_from_this(), _1));
}

void http_connection::rate_limit(int limit)
{
	if (!m_limiter_timer_active)
	{
		m_limiter_timer_active = true;
		m_limiter_timer.expires_from_now(milliseconds(250));
		m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
			, shared_from_this(), _1));
	}
	m_rate_limit = limit;
}

}

<commit_msg>completed previous fix<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/http_connection.hpp"

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <asio/ip/tcp.hpp>
#include <string>

using boost::bind;

namespace libtorrent
{

void http_connection::get(std::string const& url, time_duration timeout)
{
	std::string protocol;
	std::string hostname;
	std::string path;
	int port;
	boost::tie(protocol, hostname, port, path) = parse_url_components(url);
	std::stringstream headers;
	headers << "GET " << path << " HTTP/1.0\r\n"
		"Host:" << hostname <<
		"Connection: close\r\n"
		"\r\n\r\n";
	sendbuffer = headers.str();
	start(hostname, boost::lexical_cast<std::string>(port), timeout);
}

void http_connection::start(std::string const& hostname, std::string const& port
	, time_duration timeout)
{
	m_timeout = timeout;
	m_timer.expires_from_now(m_timeout);
	m_timer.async_wait(bind(&http_connection::on_timeout
		, boost::weak_ptr<http_connection>(shared_from_this()), _1));
	m_called = false;
	if (m_sock.is_open() && m_hostname == hostname && m_port == port)
	{
		m_parser.reset();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
	else
	{
		m_sock.close();
		tcp::resolver::query query(hostname, port);
		m_resolver.async_resolve(query, bind(&http_connection::on_resolve
			, shared_from_this(), _1, _2));
		m_hostname = hostname;
		m_port = port;
	}
}

void http_connection::on_timeout(boost::weak_ptr<http_connection> p
	, asio::error_code const& e)
{
	if (e == asio::error::operation_aborted) return;
	boost::shared_ptr<http_connection> c = p.lock();
	if (!c) return;
	if (c->m_bottled && c->m_called) return;

	if (c->m_last_receive + c->m_timeout < time_now())
	{
		c->m_called = true;
		c->m_handler(asio::error::timed_out, c->m_parser, 0, 0);
		return;
	}

	c->m_timer.expires_at(c->m_last_receive + c->m_timeout);
	c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
}

void http_connection::close()
{
	m_timer.cancel();
	m_limiter_timer.cancel();
	m_sock.close();
	m_hostname.clear();
	m_port.clear();
}

void http_connection::on_resolve(asio::error_code const& e
		, tcp::resolver::iterator i)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}
	assert(i != tcp::resolver::iterator());
	m_sock.async_connect(*i, boost::bind(&http_connection::on_connect
		, shared_from_this(), _1/*, ++i*/));
}

void http_connection::on_connect(asio::error_code const& e
	/*, tcp::resolver::iterator i*/)
{
	if (!e)
	{
		m_last_receive = time_now();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
/*	else if (i != tcp::resolver::iterator())
	{
		// The connection failed. Try the next endpoint in the list.
		m_sock.close();
		m_sock.async_connect(*i, bind(&http_connection::on_connect
			, shared_from_this(), _1, ++i));
	}
*/	else
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
	}
}

void http_connection::on_write(asio::error_code const& e)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	std::string().swap(sendbuffer);
	m_recvbuffer.resize(4096);

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_read(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	if (m_rate_limit)
	{
		m_download_quota -= bytes_transferred;
		assert(m_download_quota >= 0);
	}

	if (e == asio::error::eof)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(asio::error_code(), m_parser, 0, 0);
		return;
	}

	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	m_read_pos += bytes_transferred;
	assert(m_read_pos <= int(m_recvbuffer.size()));

	if (m_bottled || !m_parser.header_finished())
	{
		libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
			, &m_recvbuffer[0] + m_read_pos);
		m_parser.incoming(rcv_buf);
		if (!m_bottled && m_parser.header_finished())
		{
			if (m_read_pos > m_parser.body_start())
				m_handler(e, m_parser, &m_recvbuffer[0] + m_parser.body_start()
					, m_read_pos - m_parser.body_start());
			m_read_pos = 0;
			m_last_receive = time_now();
		}
		else if (m_bottled && m_parser.finished())
		{
			m_timer.cancel();
			if (m_bottled && m_called) return;
			m_called = true;
			m_handler(e, m_parser, 0, 0);
		}
	}
	else
	{
		assert(!m_bottled);
		m_handler(e, m_parser, &m_recvbuffer[0], m_read_pos);
		m_read_pos = 0;
		m_last_receive = time_now();
	}

	if (int(m_recvbuffer.size()) == m_read_pos)
		m_recvbuffer.resize((std::min)(m_read_pos + 2048, 1024*500));
	if (m_read_pos == 1024 * 500)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(asio::error::eof, m_parser, 0, 0);
		return;
	}
	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_assign_bandwidth(asio::error_code const& e)
{
	if ((e == asio::error::operation_aborted
		&& m_limiter_timer_active)
		|| !m_sock.is_open())
	{
		if (!m_bottled || !m_called)
			m_handler(e, m_parser, 0, 0);
		return;
	}
	m_limiter_timer_active = false;
	if (e) return;

	if (m_download_quota > 0) return;

	m_download_quota = m_rate_limit / 4;

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (amount_to_read > m_download_quota)
		amount_to_read = m_download_quota;

	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));

	m_limiter_timer_active = true;
	m_limiter_timer.expires_from_now(milliseconds(250));
	m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
		, shared_from_this(), _1));
}

void http_connection::rate_limit(int limit)
{
	if (!m_limiter_timer_active)
	{
		m_limiter_timer_active = true;
		m_limiter_timer.expires_from_now(milliseconds(250));
		m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
			, shared_from_this(), _1));
	}
	m_rate_limit = limit;
}

}

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "MicroTorrent"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "libTorrent (libtorrent.rakshasa.no/}"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";
		if (find_string(PID, "OP")) return "Opera";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>updated identify client<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "MicroTorrent"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "rTorrent"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";
		if (find_string(PID, "OP")) return "Opera";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/*
 *  bmpImage.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on Wed Feb 20 2008.
 *  Copyright (c) 2008 Alyssa Milburn. All rights reserved.
 *
 *  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.
 *
 */

#include "bmpImage.h"
#include "endianlove.h"
#include "streamutils.h"
#include "exceptions.h"
#include "openc2e.h"

#include <iostream> // TODO: remove me

#define BI_RGB 0
#define BI_RLE8 1
#define BI_BITFIELDS 3

bmpImage::bmpImage(mmapifstream *in, std::string n) : creaturesImage(n) {
	copied_data = false;

	char magic[2];
	in->read(magic, 2);
	if (std::string(magic, 2) != "BM")
		throw creaturesException(n + " doesn't seem to be a BMP file.");

	in->seekg(8, std::ios::cur); // skip filesize and reserved bytes

	uint32 dataoffset = read32(*in);

	uint32 biSize = read32(*in);
	if (biSize != 40) // win3.x format, which the seamonkeys files are in
		throw creaturesException(n + " is a BMP format we don't understand.");

	biWidth = read32(*in);
	biHeight = read32(*in);
	caos_assert((int)biHeight > 0);

	uint16 biPlanes = read16(*in);
	if (biPlanes != 1) // single image plane
		throw creaturesException(n + " contains BMP data we don't understand.");

	uint16 biBitCount = read16(*in);
	biCompression = read32(*in);

	// and now for some stuff we really don't care about
	uint32 biSizeImage = read32(*in);
	uint32 biXPelsPerMeter = read32(*in);
	uint32 biYPelsPerMeter = read32(*in);
	uint32 biClrUsed = read32(*in);
	uint32 biClrImportant = read32(*in);

	switch (biCompression) {
		case BI_RGB:
			break;

		case BI_RLE8:
			if (biBitCount != 8) throw creaturesException(n + " contains BMP data compressed in a way which isn't possible.");
			break;

		case BI_BITFIELDS:
		default:
			throw creaturesException(n + " contains BMP data compressed in a way we don't understand.");
	}

	switch (biBitCount)  {
		case 4:
		case 8:
			imgformat = if_paletted;
			palette = (uint8 *)(in->map + (unsigned int)in->tellg());
			break;

		case 24:
			imgformat = if_24bit;
			break;

		default:
			throw creaturesException(n + " contains BMP data of an unsupported bit depth.");
	}

	is_mutable = false;

	bmpdata = in->map + dataoffset;
	buffers = 0;

	if (biBitCount == 4) {
		char *srcdata = (char *)bmpdata;
		char *dstdata = new char[biWidth * biHeight];
		bmpdata = dstdata;
		copied_data = true;

		for (char *dest = dstdata; dest < dstdata + biWidth * biHeight; dest += biWidth) {
			uint8 pixel = 0;
			for (unsigned int i = 0; i < biWidth; i++) {
				if (i % 2 == 0) {
					pixel = *srcdata;
					srcdata++;
				}
				*(dest + i) = (pixel >> 4);
				pixel <<= 4;
			}
		}
	}

	if (biCompression == BI_RLE8) {
		std::cout << "decoding " << n << std::endl;

		// decode an RLE-compressed 8-bit image
		// TODO: sanity checking
		char *srcdata = (char *)bmpdata;
		char *dstdata = new char[biWidth * biHeight];
		for (unsigned int i = 0; i < biWidth * biHeight; i++) dstdata[i] = 0; // TODO
		bmpdata = dstdata;
		copied_data = true;

		unsigned int x = 0, y = 0;
		for (unsigned int i = 0; i < biSizeImage;) {
			unsigned char nopixels = srcdata[i]; i++;
			unsigned char val = srcdata[i]; i++;
			if (nopixels == 0) { // special
				if (val == 0) { // end of line
					x = 0;
					y += 1;
				} else if (val == 1) { // end of bitmap
					break;
				} else if (val == 2) { // delta
					unsigned char horz = srcdata[i]; i++;
					unsigned char vert = srcdata[i]; i++;
					x += horz;
					y += vert;
				} else { // absolute mode
					for (unsigned int j = 0; j < val; j++) {
						if (x + (y * biWidth) >= biHeight * biWidth) break;
						dstdata[x + (y * biWidth)] = srcdata[i];
						i++; x++;
					}
					if (val % 2 == 1) i++; // skip padding byte
				}
			} else { // run of pixels
				for (unsigned int j = 0; j < nopixels; j++) {
					if (x + (y * biWidth) >= biHeight * biWidth) break;
					dstdata[x + (y * biWidth)] = val;
					x++;
				}
			}

			while (x > biWidth) {
				x -= biWidth; y++;
			}

			if (x + (y * biWidth) >= biHeight * biWidth) break;
		}
	}

	setBlockSize(biWidth, biHeight);
}

bmpImage::~bmpImage() {
	freeData();

	if (copied_data) delete[] (char *)bmpdata;
}

void bmpImage::freeData() {
	for (unsigned int i = 0; i < m_numframes; i++) {
		delete[] (char *)buffers[i];
	}

	delete[] widths;
	delete[] heights;
	delete[] buffers;
}

void bmpImage::setBlockSize(unsigned int blockwidth, unsigned int blockheight) {
	if (buffers) freeData();
	m_numframes = 0;

	unsigned int widthinblocks = biWidth / blockwidth;
	caos_assert(widthinblocks * blockwidth == biWidth);
	unsigned int heightinblocks = biHeight / blockheight;
	caos_assert(heightinblocks * blockheight == biHeight);

	m_numframes = widthinblocks * heightinblocks;
	widths = new unsigned short[m_numframes];
	heights = new unsigned short[m_numframes];
	buffers = new void *[m_numframes];

	unsigned int pitch = biWidth;
	if (imgformat == if_24bit) pitch = (((biWidth * 3) + 3) / 4) * 4;
	else if (biCompression == BI_RGB) pitch = ((biWidth + 3) / 4) * 4;

	unsigned int curr_row = 0, curr_col = 0;
	for (unsigned int i = 0; i < m_numframes; i++) {
		widths[i] = blockwidth;
		heights[i] = blockheight;

		unsigned int buffersize = blockwidth * blockheight;
		if (imgformat == if_24bit) { buffersize *= 3; }

		buffers[i] = new char *[buffersize];

		for (unsigned int j = 0; j < blockheight; j++) {
			unsigned int srcoffset = (curr_col * blockwidth);
			unsigned int destoffset = blockwidth * j;
			unsigned int datasize = blockwidth;
			if (imgformat == if_24bit) { srcoffset *= 3; destoffset *= 3; datasize *= 3; }
			srcoffset += ((biHeight - 1) - (blockheight * curr_row) - j) * pitch;

			memcpy((char *)buffers[i] + destoffset, (char *)bmpdata + srcoffset, datasize);
		}

		curr_col++;
		if (curr_col == widthinblocks) {
			curr_col = 0;
			curr_row++;
		}
	}
}

/* vim: set noet: */
<commit_msg>bmpImage: swap the palette at load time<commit_after>/*
 *  bmpImage.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on Wed Feb 20 2008.
 *  Copyright (c) 2008 Alyssa Milburn. All rights reserved.
 *
 *  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.
 *
 */

#include "bmpImage.h"
#include "endianlove.h"
#include "streamutils.h"
#include "exceptions.h"
#include "openc2e.h"

#include <iostream> // TODO: remove me

#define BI_RGB 0
#define BI_RLE8 1
#define BI_BITFIELDS 3

bmpImage::bmpImage(mmapifstream *in, std::string n) : creaturesImage(n) {
	copied_data = false;

	char magic[2];
	in->read(magic, 2);
	if (std::string(magic, 2) != "BM")
		throw creaturesException(n + " doesn't seem to be a BMP file.");

	in->seekg(8, std::ios::cur); // skip filesize and reserved bytes

	uint32 dataoffset = read32(*in);

	uint32 biSize = read32(*in);
	if (biSize != 40) // win3.x format, which the seamonkeys files are in
		throw creaturesException(n + " is a BMP format we don't understand.");

	biWidth = read32(*in);
	biHeight = read32(*in);
	caos_assert((int)biHeight > 0);

	uint16 biPlanes = read16(*in);
	if (biPlanes != 1) // single image plane
		throw creaturesException(n + " contains BMP data we don't understand.");

	uint16 biBitCount = read16(*in);
	biCompression = read32(*in);

	// and now for some stuff we really don't care about
	uint32 biSizeImage = read32(*in);
	uint32 biXPelsPerMeter = read32(*in);
	uint32 biYPelsPerMeter = read32(*in);
	uint32 biClrUsed = read32(*in);
	uint32 biClrImportant = read32(*in);

	switch (biCompression) {
		case BI_RGB:
			break;

		case BI_RLE8:
			if (biBitCount != 8) throw creaturesException(n + " contains BMP data compressed in a way which isn't possible.");
			break;

		case BI_BITFIELDS:
		default:
			throw creaturesException(n + " contains BMP data compressed in a way we don't understand.");
	}

	switch (biBitCount)  {
		case 4:
		case 8:
			{
			imgformat = if_paletted;
			uint8 *filepalette = (uint8 *)(in->map + (unsigned int)in->tellg());
			palette = new uint8[256 * 4];
			for (unsigned int i = 0; i < (biBitCount == 4 ? 16 : 256); i++) {
				palette[i * 4] = filepalette[(i * 4) + 2];
				palette[(i * 4) + 1] = filepalette[(i * 4) + 1];
				palette[(i * 4) + 2] = filepalette[i * 4];
				palette[(i * 4) + 3] = 0;
			}
			}
			break;

		case 24:
			imgformat = if_24bit;
			break;

		default:
			throw creaturesException(n + " contains BMP data of an unsupported bit depth.");
	}

	is_mutable = false;

	bmpdata = in->map + dataoffset;
	buffers = 0;

	if (biBitCount == 4) {
		char *srcdata = (char *)bmpdata;
		char *dstdata = new char[biWidth * biHeight];
		bmpdata = dstdata;
		copied_data = true;

		for (char *dest = dstdata; dest < dstdata + biWidth * biHeight; dest += biWidth) {
			uint8 pixel = 0;
			for (unsigned int i = 0; i < biWidth; i++) {
				if (i % 2 == 0) {
					pixel = *srcdata;
					srcdata++;
				}
				*(dest + i) = (pixel >> 4);
				pixel <<= 4;
			}
		}
	}

	if (biCompression == BI_RLE8) {
		std::cout << "decoding " << n << std::endl;

		// decode an RLE-compressed 8-bit image
		// TODO: sanity checking
		char *srcdata = (char *)bmpdata;
		char *dstdata = new char[biWidth * biHeight];
		for (unsigned int i = 0; i < biWidth * biHeight; i++) dstdata[i] = 0; // TODO
		bmpdata = dstdata;
		copied_data = true;

		unsigned int x = 0, y = 0;
		for (unsigned int i = 0; i < biSizeImage;) {
			unsigned char nopixels = srcdata[i]; i++;
			unsigned char val = srcdata[i]; i++;
			if (nopixels == 0) { // special
				if (val == 0) { // end of line
					x = 0;
					y += 1;
				} else if (val == 1) { // end of bitmap
					break;
				} else if (val == 2) { // delta
					unsigned char horz = srcdata[i]; i++;
					unsigned char vert = srcdata[i]; i++;
					x += horz;
					y += vert;
				} else { // absolute mode
					for (unsigned int j = 0; j < val; j++) {
						if (x + (y * biWidth) >= biHeight * biWidth) break;
						dstdata[x + (y * biWidth)] = srcdata[i];
						i++; x++;
					}
					if (val % 2 == 1) i++; // skip padding byte
				}
			} else { // run of pixels
				for (unsigned int j = 0; j < nopixels; j++) {
					if (x + (y * biWidth) >= biHeight * biWidth) break;
					dstdata[x + (y * biWidth)] = val;
					x++;
				}
			}

			while (x > biWidth) {
				x -= biWidth; y++;
			}

			if (x + (y * biWidth) >= biHeight * biWidth) break;
		}
	}

	setBlockSize(biWidth, biHeight);
}

bmpImage::~bmpImage() {
	freeData();

	if (copied_data) delete[] (char *)bmpdata;
}

void bmpImage::freeData() {
	for (unsigned int i = 0; i < m_numframes; i++) {
		delete[] (char *)buffers[i];
	}

	delete[] widths;
	delete[] heights;
	delete[] buffers;
}

void bmpImage::setBlockSize(unsigned int blockwidth, unsigned int blockheight) {
	if (buffers) freeData();
	m_numframes = 0;

	unsigned int widthinblocks = biWidth / blockwidth;
	caos_assert(widthinblocks * blockwidth == biWidth);
	unsigned int heightinblocks = biHeight / blockheight;
	caos_assert(heightinblocks * blockheight == biHeight);

	m_numframes = widthinblocks * heightinblocks;
	widths = new unsigned short[m_numframes];
	heights = new unsigned short[m_numframes];
	buffers = new void *[m_numframes];

	unsigned int pitch = biWidth;
	if (imgformat == if_24bit) pitch = (((biWidth * 3) + 3) / 4) * 4;
	else if (biCompression == BI_RGB) pitch = ((biWidth + 3) / 4) * 4;

	unsigned int curr_row = 0, curr_col = 0;
	for (unsigned int i = 0; i < m_numframes; i++) {
		widths[i] = blockwidth;
		heights[i] = blockheight;

		unsigned int buffersize = blockwidth * blockheight;
		if (imgformat == if_24bit) { buffersize *= 3; }

		buffers[i] = new char *[buffersize];

		for (unsigned int j = 0; j < blockheight; j++) {
			unsigned int srcoffset = (curr_col * blockwidth);
			unsigned int destoffset = blockwidth * j;
			unsigned int datasize = blockwidth;
			if (imgformat == if_24bit) { srcoffset *= 3; destoffset *= 3; datasize *= 3; }
			srcoffset += ((biHeight - 1) - (blockheight * curr_row) - j) * pitch;

			memcpy((char *)buffers[i] + destoffset, (char *)bmpdata + srcoffset, datasize);
		}

		curr_col++;
		if (curr_col == widthinblocks) {
			curr_col = 0;
			curr_row++;
		}
	}
}

/* vim: set noet: */
<|endoftext|>


<commit_before>// Copyright (c) 2013 Joshua Beitler, Mirus contributors

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef _MIRUS_KERNEL_IDT_H_
#define _MIRUS_KERNEL_IDT_H_

#include <mem/memory.hpp>

namespace mirus {
    class idt_entry {
    public:
        unsigned short base_lo;
        unsigned short sel;        /* Our kernel segment goes here! */
        unsigned char always0;     /* This will ALWAYS be set to 0! */
        unsigned char flags;       /* Set using the above table! */
        unsigned short base_hi;
    } __attribute__ ((__packed__));

    class idt_ptr {
    public:
        unsigned short limit;
        unsigned long base;
    } __attribute__ ((__packed__));

    class idt {
    public:
        static void set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags);
        static void install();
    };
}

// namespace mirus {
//     /* Defines an IDT entry */
//     class idt_entry {
//     public:
//         unsigned short base_lo;
//         unsigned short sel;        /* Our kernel segment goes here! */
//         unsigned char always0;     /* This will ALWAYS be set to 0! */
//         unsigned char flags;       /* Set using the above table! */
//         unsigned short base_hi;
//     } __attribute__ ((__packed__));

//     class idt_ptr {
//     public:
//         unsigned short limit;
//         unsigned long base;
//     } __attribute__ ((__packed__));

//     void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags);
//     void idt_install();
// }

#endif<commit_msg>Updated IDT<commit_after>// Copyright (c) 2013 Joshua Beitler, Mirus contributors

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef _MIRUS_KERNEL_IDT_H_
#define _MIRUS_KERNEL_IDT_H_

#include <mem/memory.hpp>

namespace mirus {
    class idt_entry {
    public:
        unsigned short base_lo;
        unsigned short sel;        // Our kernel segment goes here!
        unsigned char always0;     // This will ALWAYS be set to 0!
        unsigned char flags;       // Set using the above table!
        unsigned short base_hi;
    } __attribute__ ((__packed__));

    class idt_ptr {
    public:
        unsigned short limit;
        unsigned long base;
    } __attribute__ ((__packed__));

    class idt {
    public:
        static void set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags);
        static void install();
    };
}

#endif<|endoftext|>


<commit_before>//
// Copyright (C) 2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <sipxunit/TestUtilities.h>

#include <mp/MpOutputDeviceManager.h>
#include <mp/MpAudioBuf.h>
#include <mp/MpSineWaveGeneratorDeviceDriver.h>
#include <os/OsTask.h>
#include <os/OsEvent.h>

#ifdef RTL_ENABLED // [
#  include "rtl_macro.h"
#else  // RTL_ENABLED ][
#  define RTL_WRITE
#  define RTL_BLOCK
#  define RTL_START
#endif // RTL_ENABLED ]

#define TEST_SAMPLES_PER_FRAME_SIZE   80
#define BUFFER_NUM                    50
#define TEST_SAMPLES_PER_SECOND       8000
#define TEST_MIXER_BUFFER_LENGTH      10
#define TEST_SAMPLE_DATA_LENGTH_SEC   5  // test length in seconds
#define TEST_SAMPLE_DATA_SIZE         (TEST_SAMPLES_PER_SECOND*TEST_SAMPLE_DATA_LENGTH_SEC)
#define TEST_SAMPLE_DATA_MAGNITUDE    32000
#define TEST_SAMPLE_DATA_PERIOD       7  // in milliseconds

//#define USE_TEST_DRIVER

#ifdef USE_TEST_DRIVER // USE_TEST_DRIVER [
#include <mp/MpodBufferRecorder.h>
#define OUTPUT_DRIVER MpodBufferRecorder
#define OUTPUT_DRIVER_CONSTRUCTOR_PARAMS "default", TEST_SAMPLE_DATA_SIZE*1000/TEST_SAMPLES_PER_SECOND

#elif defined(WIN32) // USE_TEST_DRIVER ][ WIN32
#error No output driver for Windows exist!

#elif defined(__pingtel_on_posix__) // WIN32 ][ __pingtel_on_posix__
#include <mp/MpodOSS.h>
#define OUTPUT_DRIVER MpodOSS
#define OUTPUT_DRIVER_CONSTRUCTOR_PARAMS "/dev/dsp"

#else // __pingtel_on_possix__ ]
#error Unknown platform!
#endif

MpAudioSample sampleData[TEST_SAMPLE_DATA_SIZE];
UtlBoolean sampleDataInitialized=FALSE;

void calculateSampleData()
{
   if (sampleDataInitialized)
      return;

   for (int i=0; i<TEST_SAMPLE_DATA_SIZE; i++)
   {
      sampleData[i] =
         MpSineWaveGeneratorDeviceDriver::calculateSample(0,
                                                          TEST_SAMPLE_DATA_MAGNITUDE,
                                                          TEST_SAMPLE_DATA_PERIOD,
                                                          i,
                                                          TEST_SAMPLES_PER_FRAME_SIZE,
                                                          TEST_SAMPLES_PER_SECOND);
   }

   sampleDataInitialized = TRUE;
}

/**
 * Unittest for MpOutputDeviceManager
 */
class MpOutputDeviceDriverTest : public CppUnit::TestCase
{
   CPPUNIT_TEST_SUITE(MpOutputDeviceDriverTest);
   CPPUNIT_TEST(testCreate);
   CPPUNIT_TEST(testAddRemoveToManager);
   CPPUNIT_TEST(testEnableDisable);
   CPPUNIT_TEST(testEnableDisableFast);
   // This is disabled, as it gives very bad sound quality
   // and may be used only for very first driver testing.
   //CPPUNIT_TEST(testDirectWrite);
   CPPUNIT_TEST(testTickerNotification);
   CPPUNIT_TEST_SUITE_END();

public:

   void setUp()
   {
      // Create pool for data buffers
      mpPool = new MpBufPool(TEST_SAMPLES_PER_FRAME_SIZE * sizeof(MpAudioSample)
                             + MpArrayBuf::getHeaderSize(), BUFFER_NUM);
      CPPUNIT_ASSERT(mpPool != NULL);

      // Create pool for buffer headers
      mpHeadersPool = new MpBufPool(sizeof(MpAudioBuf), BUFFER_NUM);
      CPPUNIT_ASSERT(mpHeadersPool != NULL);

      // Set mpHeadersPool as default pool for audio and data pools.
      MpAudioBuf::smpDefaultPool = mpHeadersPool;
      MpDataBuf::smpDefaultPool = mpHeadersPool;
   }

   void tearDown()
   {
      if (mpPool != NULL)
      {
         delete mpPool;
      }
      if (mpHeadersPool != NULL)
      {
         delete mpHeadersPool;
      }
   }

   void testCreate()
   {
      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
   }

   void testAddRemoveToManager()
   {
      OUTPUT_DRIVER device(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      MpOutputDeviceHandle deviceId;

      {
         // Test with direct write mode
         MpOutputDeviceManager deviceManager(TEST_SAMPLES_PER_FRAME_SIZE,
            TEST_SAMPLES_PER_SECOND,
            0);

         deviceId = deviceManager.addDevice(&device);
         CPPUNIT_ASSERT(deviceId > 0);
         CPPUNIT_ASSERT(deviceManager.removeDevice(deviceId) == &device);
      }

      {
         // Test with mixer mode
         MpOutputDeviceManager deviceManager(TEST_SAMPLES_PER_FRAME_SIZE,
                                             TEST_SAMPLES_PER_SECOND,
                                             TEST_MIXER_BUFFER_LENGTH);

         deviceId = deviceManager.addDevice(&device);
         CPPUNIT_ASSERT(deviceId > 0);
         CPPUNIT_ASSERT(deviceManager.removeDevice(deviceId) == &device);
      }
   }

   void testEnableDisable()
   {
      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);
      OsTask::delay(50);
      driver.disableDevice();
   }

   void testEnableDisableFast()
   {
      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);
      driver.disableDevice();
   }

   void testDirectWrite()
   {
      calculateSampleData();

      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);

      // Write some data to device.
      for (int frame=0; frame<TEST_SAMPLE_DATA_SIZE/TEST_SAMPLES_PER_FRAME_SIZE; frame++)
      {
         OsTask::delay(1000*TEST_SAMPLES_PER_FRAME_SIZE/TEST_SAMPLES_PER_SECOND);
         driver.pushFrame(TEST_SAMPLES_PER_FRAME_SIZE, sampleData + TEST_SAMPLES_PER_FRAME_SIZE*frame);
      }

      driver.disableDevice();
   }

   void testTickerNotification()
   {
      OsEvent notificationEvent;

      RTL_START(1000000);

      calculateSampleData();

      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);
      driver.setTickerNotification(&notificationEvent);

      // Write some data to device.
      for (int frame=0; frame<TEST_SAMPLE_DATA_SIZE/TEST_SAMPLES_PER_FRAME_SIZE; frame++)
      {
         notificationEvent.wait(OsTime(500));
         notificationEvent.reset();
         RTL_BLOCK("test ticker loop");
         driver.pushFrame(TEST_SAMPLES_PER_FRAME_SIZE, sampleData + TEST_SAMPLES_PER_FRAME_SIZE*frame);
      }

      driver.disableDevice();

      RTL_WRITE("testTickerNotification.rtl");
   }

protected:
   MpBufPool *mpPool;         ///< Pool for data buffers
   MpBufPool *mpHeadersPool;  ///< Pool for buffers headers

};

CPPUNIT_TEST_SUITE_REGISTRATION(MpOutputDeviceDriverTest);
<commit_msg>MpOutputFrameworkTest: Fix test class name and build warnings.<commit_after>//
// Copyright (C) 2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <sipxunit/TestUtilities.h>

#include <mp/MpOutputDeviceManager.h>
#include <mp/MpAudioBuf.h>
#include <mp/MpSineWaveGeneratorDeviceDriver.h>
#include <os/OsTask.h>
#include <os/OsEvent.h>

#ifdef RTL_ENABLED // [
#  include "rtl_macro.h"
#else  // RTL_ENABLED ][
#  define RTL_WRITE(x)
#  define RTL_BLOCK(x)
#  define RTL_START(x)
#endif // RTL_ENABLED ]

#define TEST_SAMPLES_PER_FRAME_SIZE   80
#define BUFFER_NUM                    50
#define TEST_SAMPLES_PER_SECOND       8000
#define TEST_MIXER_BUFFER_LENGTH      10
#define TEST_SAMPLE_DATA_LENGTH_SEC   5  // test length in seconds
#define TEST_SAMPLE_DATA_SIZE         (TEST_SAMPLES_PER_SECOND*TEST_SAMPLE_DATA_LENGTH_SEC)
#define TEST_SAMPLE_DATA_MAGNITUDE    32000
#define TEST_SAMPLE_DATA_PERIOD       7  // in milliseconds

//#define USE_TEST_DRIVER

#ifdef USE_TEST_DRIVER // USE_TEST_DRIVER [
#include <mp/MpodBufferRecorder.h>
#define OUTPUT_DRIVER MpodBufferRecorder
#define OUTPUT_DRIVER_CONSTRUCTOR_PARAMS "default", TEST_SAMPLE_DATA_SIZE*1000/TEST_SAMPLES_PER_SECOND

#elif defined(WIN32) // USE_TEST_DRIVER ][ WIN32
#error No output driver for Windows exist!

#elif defined(__pingtel_on_posix__) // WIN32 ][ __pingtel_on_posix__
#include <mp/MpodOSS.h>
#define OUTPUT_DRIVER MpodOSS
#define OUTPUT_DRIVER_CONSTRUCTOR_PARAMS "/dev/dsp"

#else // __pingtel_on_possix__ ]
#error Unknown platform!
#endif

MpAudioSample sampleData[TEST_SAMPLE_DATA_SIZE];
UtlBoolean sampleDataInitialized=FALSE;

void calculateSampleData()
{
   if (sampleDataInitialized)
      return;

   for (int i=0; i<TEST_SAMPLE_DATA_SIZE; i++)
   {
      sampleData[i] =
         MpSineWaveGeneratorDeviceDriver::calculateSample(0,
                                                          TEST_SAMPLE_DATA_MAGNITUDE,
                                                          TEST_SAMPLE_DATA_PERIOD,
                                                          i,
                                                          TEST_SAMPLES_PER_FRAME_SIZE,
                                                          TEST_SAMPLES_PER_SECOND);
   }

   sampleDataInitialized = TRUE;
}

/**
 * Unittest for MpOutputDeviceManager
 */
class MpOutputFrameworkTest : public CppUnit::TestCase
{
   CPPUNIT_TEST_SUITE(MpOutputFrameworkTest);
   CPPUNIT_TEST(testCreate);
   CPPUNIT_TEST(testAddRemoveToManager);
   CPPUNIT_TEST(testEnableDisable);
   CPPUNIT_TEST(testEnableDisableFast);
   // This is disabled, as it gives very bad sound quality
   // and may be used only for very first driver testing.
   //CPPUNIT_TEST(testDirectWrite);
   CPPUNIT_TEST(testTickerNotification);
   CPPUNIT_TEST_SUITE_END();

public:

   void setUp()
   {
      // Create pool for data buffers
      mpPool = new MpBufPool(TEST_SAMPLES_PER_FRAME_SIZE * sizeof(MpAudioSample)
                             + MpArrayBuf::getHeaderSize(), BUFFER_NUM);
      CPPUNIT_ASSERT(mpPool != NULL);

      // Create pool for buffer headers
      mpHeadersPool = new MpBufPool(sizeof(MpAudioBuf), BUFFER_NUM);
      CPPUNIT_ASSERT(mpHeadersPool != NULL);

      // Set mpHeadersPool as default pool for audio and data pools.
      MpAudioBuf::smpDefaultPool = mpHeadersPool;
      MpDataBuf::smpDefaultPool = mpHeadersPool;
   }

   void tearDown()
   {
      if (mpPool != NULL)
      {
         delete mpPool;
      }
      if (mpHeadersPool != NULL)
      {
         delete mpHeadersPool;
      }
   }

   void testCreate()
   {
      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
   }

   void testAddRemoveToManager()
   {
      OUTPUT_DRIVER device(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      MpOutputDeviceHandle deviceId;

      {
         // Test with direct write mode
         MpOutputDeviceManager deviceManager(TEST_SAMPLES_PER_FRAME_SIZE,
            TEST_SAMPLES_PER_SECOND,
            0);

         deviceId = deviceManager.addDevice(&device);
         CPPUNIT_ASSERT(deviceId > 0);
         CPPUNIT_ASSERT(deviceManager.removeDevice(deviceId) == &device);
      }

      {
         // Test with mixer mode
         MpOutputDeviceManager deviceManager(TEST_SAMPLES_PER_FRAME_SIZE,
                                             TEST_SAMPLES_PER_SECOND,
                                             TEST_MIXER_BUFFER_LENGTH);

         deviceId = deviceManager.addDevice(&device);
         CPPUNIT_ASSERT(deviceId > 0);
         CPPUNIT_ASSERT(deviceManager.removeDevice(deviceId) == &device);
      }
   }

   void testEnableDisable()
   {
      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);
      OsTask::delay(50);
      driver.disableDevice();
   }

   void testEnableDisableFast()
   {
      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);
      driver.disableDevice();
   }

   void testDirectWrite()
   {
      calculateSampleData();

      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);

      // Write some data to device.
      for (int frame=0; frame<TEST_SAMPLE_DATA_SIZE/TEST_SAMPLES_PER_FRAME_SIZE; frame++)
      {
         OsTask::delay(1000*TEST_SAMPLES_PER_FRAME_SIZE/TEST_SAMPLES_PER_SECOND);
         driver.pushFrame(TEST_SAMPLES_PER_FRAME_SIZE, sampleData + TEST_SAMPLES_PER_FRAME_SIZE*frame);
      }

      driver.disableDevice();
   }

   void testTickerNotification()
   {
      OsEvent notificationEvent;

      RTL_START(1000000);

      calculateSampleData();

      OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS);
      driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0);
      driver.setTickerNotification(&notificationEvent);

      // Write some data to device.
      for (int frame=0; frame<TEST_SAMPLE_DATA_SIZE/TEST_SAMPLES_PER_FRAME_SIZE; frame++)
      {
         notificationEvent.wait(OsTime(500));
         notificationEvent.reset();
         RTL_BLOCK("test ticker loop");
         driver.pushFrame(TEST_SAMPLES_PER_FRAME_SIZE, sampleData + TEST_SAMPLES_PER_FRAME_SIZE*frame);
      }

      driver.disableDevice();

      RTL_WRITE("testTickerNotification.rtl");
   }

protected:
   MpBufPool *mpPool;         ///< Pool for data buffers
   MpBufPool *mpHeadersPool;  ///< Pool for buffers headers

};

CPPUNIT_TEST_SUITE_REGISTRATION(MpOutputFrameworkTest);
<|endoftext|>