<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgSim/LightPointNode>
#include <osgSim/LightPointSystem>

#include "LightPointDrawable.h"

#include <osg/Timer>
#include <osg/BoundingBox>
#include <osg/BlendFunc>
#include <osg/Material>

#include <osgUtil/CullVisitor>

#include <typeinfo>

namespace osgSim
{

osg::StateSet* getSingletonLightPointSystemSet()
{
    static osg::ref_ptr<osg::StateSet> s_stateset = 0;
    if (!s_stateset)
    {
        s_stateset = new osg::StateSet;
        // force light point nodes to be drawn after everything else by picking a renderin bin number after
        // the transparent bin.
        s_stateset->setRenderBinDetails(20,"DepthSortedBin");
    }
    return s_stateset.get();
}

LightPointNode::LightPointNode():
    _minPixelSize(0.0f),
    _maxPixelSize(30.0f),
    _maxVisibleDistance2(FLT_MAX),
    _lightSystem(0)
{
    setStateSet(getSingletonLightPointSystemSet());
}

/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
LightPointNode::LightPointNode(const LightPointNode& lpn,const osg::CopyOp& copyop):
    osg::Node(lpn,copyop),
    _lightPointList(lpn._lightPointList),
    _minPixelSize(lpn._minPixelSize),
    _maxPixelSize(lpn._maxPixelSize),
    _maxVisibleDistance2(lpn._maxVisibleDistance2),
    _lightSystem(lpn._lightSystem)
{
}

unsigned int LightPointNode::addLightPoint(const LightPoint& lp)
{
    unsigned int num = _lightPointList.size();
    _lightPointList.push_back(lp);
    dirtyBound();
    return num;
}

void LightPointNode::removeLightPoint(unsigned int pos)
{
    if (pos<_lightPointList.size())
    {
        _lightPointList.erase(_lightPointList.begin()+pos);
        dirtyBound();
    }
    dirtyBound();
}

osg::BoundingSphere LightPointNode::computeBound() const
{
    osg::BoundingSphere bsphere;
    bsphere.init();
    _bbox.init();

    if (_lightPointList.empty())
    {
        return bsphere;
    }

    LightPointList::const_iterator itr;
    for(itr=_lightPointList.begin();
        itr!=_lightPointList.end();
        ++itr)
    {
        _bbox.expandBy(itr->_position);
    }

    bsphere.set(_bbox.center(),0.0f);

    for(itr=_lightPointList.begin();
        itr!=_lightPointList.end();
        ++itr)
    {
        osg::Vec3 dv(itr->_position-bsphere.center());
        float radius = dv.length()+itr->_radius;
        if (bsphere.radius()<radius) bsphere.radius()=radius;
    }

    bsphere.radius()+=1.0f;
    return bsphere;
}

void LightPointNode::traverse(osg::NodeVisitor& nv)
{
    if (_lightPointList.empty())
    {
        // no light points so no op.
        return;
    }

    //#define USE_TIMER
    #ifdef USE_TIMER
    osg::Timer timer;
    osg::Timer_t t1=0,t2=0,t3=0,t4=0,t5=0,t6=0,t7=0,t8=0;
    #endif

#ifdef USE_TIMER
    t1 = timer.tick();
#endif

    osgUtil::CullVisitor* cv = NULL;
    if (typeid(nv)==typeid(osgUtil::CullVisitor))
    {
        cv = static_cast<osgUtil::CullVisitor*>(&nv);
    }

#ifdef USE_TIMER
    t2 = timer.tick();
#endif

    // should we disabled small feature culling here?
    if (cv /*&& !cv->isCulled(_bbox)*/)
    {

        osg::Matrix matrix = cv->getModelViewMatrix();
        osg::RefMatrix& projection = cv->getProjectionMatrix();
        osgUtil::StateGraph* rg = cv->getCurrentStateGraph();

        if (rg->leaves_empty())
        {
            // this is first leaf to be added to StateGraph
            // and therefore should not already know to current render bin,
            // so need to add it.
            cv->getCurrentRenderBin()->addStateGraph(rg);
        }

#ifdef USE_TIMER
        t3 = timer.tick();
#endif

        LightPointDrawable* drawable = NULL;
        osg::Referenced* object = rg->getUserData();
        if (object)
        {
            if (typeid(*object)==typeid(LightPointDrawable))
            {
                // resuse the user data attached to the render graph.
                drawable = static_cast<LightPointDrawable*>(object);

            }
            else
            {
                // will need to replace UserData.
                osg::notify(osg::WARN) << "Warning: Replacing osgUtil::StateGraph::_userData to support osgSim::LightPointNode, may have undefined results."<<std::endl;
            }
        }

        if (!drawable)
        {
            // set it for the frst time.
            drawable = new LightPointDrawable;
            rg->setUserData(drawable);

            if (cv->getFrameStamp())
            {
                drawable->setReferenceTime(cv->getFrameStamp()->getReferenceTime());
            }
        }

        // search for a drawable in the RenderLead list equal to the attached the one attached to StateGraph user data
        // as this will be our special light point drawable.
        osgUtil::StateGraph::LeafList::iterator litr;
        for(litr = rg->_leaves.begin();
            litr != rg->_leaves.end() && (*litr)->_drawable!=drawable;
            ++litr)
        {}

        if (litr == rg->_leaves.end())
        {
            // havn't found the drawable added in the RenderLeaf list, there this my be the
            // first time through LightPointNode in this frame, so need to add drawable into the StateGraph RenderLeaf list
            // and update its time signatures.

            drawable->reset();
            rg->addLeaf(new osgUtil::RenderLeaf(drawable,&projection,NULL,FLT_MAX));

            // need to update the drawable's frame count.
            if (cv->getFrameStamp())
            {
                drawable->updateReferenceTime(cv->getFrameStamp()->getReferenceTime());
            }

        }

#ifdef USE_TIMER
        t4 = timer.tick();
#endif

#ifdef USE_TIMER
        t7 = timer.tick();
#endif

        if (cv->getComputeNearFarMode() != osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR)
            cv->updateCalculatedNearFar(matrix,_bbox);

        const float minimumIntensity = 1.0f/256.0f;
        const osg::Vec3 eyePoint = cv->getEyeLocal();

        double time=drawable->getReferenceTime();
        double timeInterval=drawable->getReferenceTimeInterval();

        const osg::Polytope clipvol(cv->getCurrentCullingSet().getFrustum());
        const bool computeClipping = false;//(clipvol.getCurrentMask()!=0);

        //LightPointDrawable::ColorPosition cp;
        for(LightPointList::iterator itr=_lightPointList.begin();
            itr!=_lightPointList.end();
            ++itr)
        {
            const LightPoint& lp = *itr;

	    if (!lp._on) continue;

            const osg::Vec3& position = lp._position;

            // skip light point if it is not contianed in the view frustum.
            if (computeClipping && !clipvol.contains(position)) continue;

            // delta vector between eyepoint and light point.
            osg::Vec3 dv(eyePoint-position);

            float intensity = (_lightSystem.valid()) ? _lightSystem->getIntensity() : lp._intensity;

            // slip light point if it is intensity is 0.0 or negative.
            if (intensity<=minimumIntensity) continue;

            if (_maxVisibleDistance2!=FLT_MAX)
            {
                if (dv.length2()>_maxVisibleDistance2) continue;
            }

            osg::Vec4 color = lp._color;

            // check the sector.
            if (lp._sector.valid())
            {
                intensity *= (*lp._sector)(dv);

                // slip light point if it is intensity is 0.0 or negative.
                if (intensity<=minimumIntensity) continue;

            }

            // temporary accounting of intensity.
            //color *= intensity;

            // check the blink sequence.
            bool doBlink = lp._blinkSequence.valid();
            if (doBlink && _lightSystem.valid())
                doBlink = (_lightSystem->getAnimationState() == LightPointSystem::ANIMATION_ON);

            if (doBlink)
            {
                osg::Vec4 bs = lp._blinkSequence->color(time,timeInterval);
                color[0] *= bs[0];
                color[1] *= bs[1];
                color[2] *= bs[2];
                color[3] *= bs[3];
            }

            // if alpha value is less than the min intentsive then skip
            if (color[3]<=minimumIntensity) continue;

            float pixelSize = cv->pixelSize(position,lp._radius);

//            cout << "pixelsize = "<<pixelSize<<endl;

            // adjust pixel size to account for intensity.
            if (intensity!=1.0) pixelSize *= sqrt(intensity);

            // round up to the minimum pixel size if required.
            if (pixelSize<_minPixelSize) pixelSize = _minPixelSize;

            osg::Vec3 xpos(position*matrix);

            if (lp._blendingMode==LightPoint::BLENDED)
            {
                if (pixelSize<1.0f)
                {
                    // need to use alpha blending...
                    //color[3] = pixelSize;
                    color[3] *= osg::square(pixelSize);

                    if (color[3]<=minimumIntensity) continue;

                    drawable->addBlendedLightPoint(0, xpos,color);
                }
                else if (pixelSize<_maxPixelSize)
                {

                    unsigned int lowerBoundPixelSize = (unsigned int)pixelSize;
                    //float remainder = pixelSize-(float)lowerBoundPixelSize;
                    float remainder = osg::square(pixelSize-(float)lowerBoundPixelSize);
                    float alpha = color[3];
                    drawable->addBlendedLightPoint(lowerBoundPixelSize-1, xpos,color);

                    color[3] = alpha*remainder;
                    drawable->addBlendedLightPoint(lowerBoundPixelSize, xpos,color);
                }
                else // use a billboard geometry.
                {
                    drawable->addBlendedLightPoint((unsigned int)(_maxPixelSize-1.0), xpos,color);
                }
            }
            else // ADDITIVE blending.
            {
                if (pixelSize<1.0f)
                {
                    // need to use alpha blending...
                    //color[3] = pixelSize;
                    color[3] *= osg::square(pixelSize);

                    if (color[3]<=minimumIntensity) continue;

                    drawable->addAdditiveLightPoint(0, xpos,color);
                }
                else if (pixelSize<_maxPixelSize)
                {

                    unsigned int lowerBoundPixelSize = (unsigned int)pixelSize;
                    //float remainder = pixelSize-(float)lowerBoundPixelSize;
                    float remainder = osg::square(pixelSize-(float)lowerBoundPixelSize);
                    float alpha = color[3];
                    color[3] = alpha*(1.0f-remainder);
                    drawable->addAdditiveLightPoint(lowerBoundPixelSize-1, xpos,color);

                    color[3] = alpha*remainder;
                    drawable->addAdditiveLightPoint(lowerBoundPixelSize, xpos,color);
                }
                else // use a billboard geometry.
                {
                    drawable->addAdditiveLightPoint((unsigned int)(_maxPixelSize-1.0), xpos,color);
                }
            }
        }

#ifdef USE_TIMER
        t8 = timer.tick();
#endif

    }
#ifdef USE_TIMER
    cout << "compute"<<endl;
    cout << "  t2-t1="<<t2-t1<<endl;
    cout << "  t4-t3="<<t4-t3<<endl;
    cout << "  t6-t5="<<t6-t5<<endl;
    cout << "  t8-t7="<<t8-t7<<endl;
    cout << "_lightPointList.size()="<<_lightPointList.size()<<endl;
    cout << "  t8-t7/size = "<<(float)(t8-t7)/(float)_lightPointList.size()<<endl;
#endif
}

} // end of namespace
<commit_msg>From Brede Johansen, "some tweaks to the osgSim lightpoints.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgSim/LightPointNode>
#include <osgSim/LightPointSystem>

#include "LightPointDrawable.h"

#include <osg/Timer>
#include <osg/BoundingBox>
#include <osg/BlendFunc>
#include <osg/Material>

#include <osgUtil/CullVisitor>

#include <typeinfo>

namespace osgSim
{

osg::StateSet* getSingletonLightPointSystemSet()
{
    static osg::ref_ptr<osg::StateSet> s_stateset = 0;
    if (!s_stateset)
    {
        s_stateset = new osg::StateSet;
        // force light point nodes to be drawn after everything else by picking a renderin bin number after
        // the transparent bin.
        s_stateset->setRenderBinDetails(20,"DepthSortedBin");
    }
    return s_stateset.get();
}

LightPointNode::LightPointNode():
    _minPixelSize(0.0f),
    _maxPixelSize(30.0f),
    _maxVisibleDistance2(FLT_MAX),
    _lightSystem(0)
{
    setStateSet(getSingletonLightPointSystemSet());
}

/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
LightPointNode::LightPointNode(const LightPointNode& lpn,const osg::CopyOp& copyop):
    osg::Node(lpn,copyop),
    _lightPointList(lpn._lightPointList),
    _minPixelSize(lpn._minPixelSize),
    _maxPixelSize(lpn._maxPixelSize),
    _maxVisibleDistance2(lpn._maxVisibleDistance2),
    _lightSystem(lpn._lightSystem)
{
}

unsigned int LightPointNode::addLightPoint(const LightPoint& lp)
{
    unsigned int num = _lightPointList.size();
    _lightPointList.push_back(lp);
    dirtyBound();
    return num;
}

void LightPointNode::removeLightPoint(unsigned int pos)
{
    if (pos<_lightPointList.size())
    {
        _lightPointList.erase(_lightPointList.begin()+pos);
        dirtyBound();
    }
    dirtyBound();
}

osg::BoundingSphere LightPointNode::computeBound() const
{
    osg::BoundingSphere bsphere;
    bsphere.init();
    _bbox.init();

    if (_lightPointList.empty())
    {
        return bsphere;
    }

    LightPointList::const_iterator itr;
    for(itr=_lightPointList.begin();
        itr!=_lightPointList.end();
        ++itr)
    {
        _bbox.expandBy(itr->_position);
    }

    bsphere.set(_bbox.center(),0.0f);

    for(itr=_lightPointList.begin();
        itr!=_lightPointList.end();
        ++itr)
    {
        osg::Vec3 dv(itr->_position-bsphere.center());
        float radius = dv.length()+itr->_radius;
        if (bsphere.radius()<radius) bsphere.radius()=radius;
    }

    bsphere.radius()+=1.0f;
    return bsphere;
}

void LightPointNode::traverse(osg::NodeVisitor& nv)
{
    if (_lightPointList.empty())
    {
        // no light points so no op.
        return;
    }

    //#define USE_TIMER
    #ifdef USE_TIMER
    osg::Timer timer;
    osg::Timer_t t1=0,t2=0,t3=0,t4=0,t5=0,t6=0,t7=0,t8=0;
    #endif

#ifdef USE_TIMER
    t1 = timer.tick();
#endif

    osgUtil::CullVisitor* cv = NULL;
    if (typeid(nv)==typeid(osgUtil::CullVisitor))
    {
        cv = static_cast<osgUtil::CullVisitor*>(&nv);
    }

#ifdef USE_TIMER
    t2 = timer.tick();
#endif

    // should we disabled small feature culling here?
    if (cv /*&& !cv->isCulled(_bbox)*/)
    {

        osg::Matrix matrix = cv->getModelViewMatrix();
        osg::RefMatrix& projection = cv->getProjectionMatrix();
        osgUtil::StateGraph* rg = cv->getCurrentStateGraph();

        if (rg->leaves_empty())
        {
            // this is first leaf to be added to StateGraph
            // and therefore should not already know to current render bin,
            // so need to add it.
            cv->getCurrentRenderBin()->addStateGraph(rg);
        }

#ifdef USE_TIMER
        t3 = timer.tick();
#endif

        LightPointDrawable* drawable = NULL;
        osg::Referenced* object = rg->getUserData();
        if (object)
        {
            if (typeid(*object)==typeid(LightPointDrawable))
            {
                // resuse the user data attached to the render graph.
                drawable = static_cast<LightPointDrawable*>(object);

            }
            else
            {
                // will need to replace UserData.
                osg::notify(osg::WARN) << "Warning: Replacing osgUtil::StateGraph::_userData to support osgSim::LightPointNode, may have undefined results."<<std::endl;
            }
        }

        if (!drawable)
        {
            // set it for the frst time.
            drawable = new LightPointDrawable;
            rg->setUserData(drawable);

            if (cv->getFrameStamp())
            {
                drawable->setReferenceTime(cv->getFrameStamp()->getReferenceTime());
            }
        }

        // search for a drawable in the RenderLead list equal to the attached the one attached to StateGraph user data
        // as this will be our special light point drawable.
        osgUtil::StateGraph::LeafList::iterator litr;
        for(litr = rg->_leaves.begin();
            litr != rg->_leaves.end() && (*litr)->_drawable!=drawable;
            ++litr)
        {}

        if (litr == rg->_leaves.end())
        {
            // havn't found the drawable added in the RenderLeaf list, there this my be the
            // first time through LightPointNode in this frame, so need to add drawable into the StateGraph RenderLeaf list
            // and update its time signatures.

            drawable->reset();
            rg->addLeaf(new osgUtil::RenderLeaf(drawable,&projection,NULL,FLT_MAX));

            // need to update the drawable's frame count.
            if (cv->getFrameStamp())
            {
                drawable->updateReferenceTime(cv->getFrameStamp()->getReferenceTime());
            }

        }

#ifdef USE_TIMER
        t4 = timer.tick();
#endif

#ifdef USE_TIMER
        t7 = timer.tick();
#endif

        if (cv->getComputeNearFarMode() != osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR)
            cv->updateCalculatedNearFar(matrix,_bbox);

        const float minimumIntensity = 1.0f/256.0f;
        const osg::Vec3 eyePoint = cv->getEyeLocal();

        double time=drawable->getReferenceTime();
        double timeInterval=drawable->getReferenceTimeInterval();

        const osg::Polytope clipvol(cv->getCurrentCullingSet().getFrustum());
        const bool computeClipping = false;//(clipvol.getCurrentMask()!=0);

        //LightPointDrawable::ColorPosition cp;
        for(LightPointList::iterator itr=_lightPointList.begin();
            itr!=_lightPointList.end();
            ++itr)
        {
            const LightPoint& lp = *itr;

	    if (!lp._on) continue;

            const osg::Vec3& position = lp._position;

            // skip light point if it is not contianed in the view frustum.
            if (computeClipping && !clipvol.contains(position)) continue;

            // delta vector between eyepoint and light point.
            osg::Vec3 dv(eyePoint-position);

            float intensity = (_lightSystem.valid()) ? _lightSystem->getIntensity() : lp._intensity;

            // slip light point if it is intensity is 0.0 or negative.
            if (intensity<=minimumIntensity) continue;

            // (SIB) Clip on distance, if close to limit, add transparancy
            float distanceFactor = 1.0f;
            if (_maxVisibleDistance2!=FLT_MAX)
            {
                if (dv.length2()>_maxVisibleDistance2) continue;
                else if (_maxVisibleDistance2 > 0)
                    distanceFactor = 1.0f - osg::square(dv.length2() / _maxVisibleDistance2);
            }

            osg::Vec4 color = lp._color;

            // check the sector.
            if (lp._sector.valid())
            {
                intensity *= (*lp._sector)(dv);

                // slip light point if it is intensity is 0.0 or negative.
                if (intensity<=minimumIntensity) continue;

            }

            // temporary accounting of intensity.
            //color *= intensity;

            // check the blink sequence.
            bool doBlink = lp._blinkSequence.valid();
            if (doBlink && _lightSystem.valid())
                doBlink = (_lightSystem->getAnimationState() == LightPointSystem::ANIMATION_ON);

            if (doBlink)
            {
                osg::Vec4 bs = lp._blinkSequence->color(time,timeInterval);
                color[0] *= bs[0];
                color[1] *= bs[1];
                color[2] *= bs[2];
                color[3] *= bs[3];
            }

            // if alpha value is less than the min intentsive then skip
            if (color[3]<=minimumIntensity) continue;

            float pixelSize = cv->pixelSize(position,lp._radius);

//            cout << "pixelsize = "<<pixelSize<<endl;

            // adjust pixel size to account for intensity.
            if (intensity!=1.0) pixelSize *= sqrt(intensity);

            // adjust alfa to account for max range (Fade on distance)
            color[3] *= distanceFactor;

            // round up to the minimum pixel size if required.
            float orgPixelSize = pixelSize;
            if (pixelSize<_minPixelSize) pixelSize = _minPixelSize;

            osg::Vec3 xpos(position*matrix);

            if (lp._blendingMode==LightPoint::BLENDED)
            {
                if (pixelSize<1.0f)
                {
                    // need to use alpha blending...
                    color[3] *= pixelSize;
                    // color[3] *= osg::square(pixelSize);

                    if (color[3]<=minimumIntensity) continue;

                    drawable->addBlendedLightPoint(0, xpos,color);
                }
                else if (pixelSize<_maxPixelSize)
                {

                    unsigned int lowerBoundPixelSize = (unsigned int)pixelSize;
                    float remainder = osg::square(pixelSize-(float)lowerBoundPixelSize);

                    // (SIB) Add transparency if pixel is clamped to minpixelsize
                    if (orgPixelSize<_minPixelSize)
                        color[3] *= (2.0/3.0) + (1.0/3.0) * sqrt(orgPixelSize / pixelSize);

                    drawable->addBlendedLightPoint(lowerBoundPixelSize-1, xpos,color);
                    color[3] *= remainder;
                    drawable->addBlendedLightPoint(lowerBoundPixelSize, xpos,color);
                }
                else // use a billboard geometry.
                {
                    drawable->addBlendedLightPoint((unsigned int)(_maxPixelSize-1.0), xpos,color);
                }
            }
            else // ADDITIVE blending.
            {
                if (pixelSize<1.0f)
                {
                    // need to use alpha blending...
                    color[3] *= pixelSize;
                    // color[3] *= osg::square(pixelSize);

                    if (color[3]<=minimumIntensity) continue;

                    drawable->addAdditiveLightPoint(0, xpos,color);
                }
                else if (pixelSize<_maxPixelSize)
                {

                    unsigned int lowerBoundPixelSize = (unsigned int)pixelSize;
                    float remainder = osg::square(pixelSize-(float)lowerBoundPixelSize);

                    // (SIB) Add transparency if pixel is clamped to minpixelsize
                    if (orgPixelSize<_minPixelSize)
                        color[3] *= (2.0/3.0) + (1.0/3.0) * sqrt(orgPixelSize / pixelSize);

                    float alpha = color[3];
                    color[3] = alpha*(1.0f-remainder);
                    drawable->addAdditiveLightPoint(lowerBoundPixelSize-1, xpos,color);
                    color[3] = alpha*remainder;
                    drawable->addAdditiveLightPoint(lowerBoundPixelSize, xpos,color);
                }
                else // use a billboard geometry.
                {
                    drawable->addAdditiveLightPoint((unsigned int)(_maxPixelSize-1.0), xpos,color);
                }
            }
        }

#ifdef USE_TIMER
        t8 = timer.tick();
#endif

    }
#ifdef USE_TIMER
    cout << "compute"<<endl;
    cout << "  t2-t1="<<t2-t1<<endl;
    cout << "  t4-t3="<<t4-t3<<endl;
    cout << "  t6-t5="<<t6-t5<<endl;
    cout << "  t8-t7="<<t8-t7<<endl;
    cout << "_lightPointList.size()="<<_lightPointList.size()<<endl;
    cout << "  t8-t7/size = "<<(float)(t8-t7)/(float)_lightPointList.size()<<endl;
#endif
}

} // end of namespace
<|endoftext|>


<commit_before>#include "output_ts_base.h"

namespace Mist {
  TSOutput::TSOutput(Socket::Connection & conn) : TS_BASECLASS(conn){
    packCounter=0;
    ts_from = 0;
    setBlocking(true);
    sendRepeatingHeaders = 0;
    appleCompat=false;
    lastHeaderTime = 0;
  }

  void TSOutput::fillPacket(char const * data, size_t dataLen, bool & firstPack, bool video, bool keyframe, uint32_t pkgPid, int & contPkg){
    do {
      if (!packData.getBytesFree()){
        if ( (sendRepeatingHeaders && thisPacket.getTime() - lastHeaderTime > sendRepeatingHeaders) || !packCounter){
          lastHeaderTime = thisPacket.getTime();
          TS::Packet tmpPack;
          tmpPack.FromPointer(TS::PAT);
          tmpPack.setContinuityCounter(++contPAT);
          sendTS(tmpPack.checkAndGetBuffer());
          sendTS(TS::createPMT(selectedTracks, myMeta, ++contPMT));
          sendTS(TS::createSDT(streamName, ++contSDT));
          packCounter += 3;
        }
        sendTS(packData.checkAndGetBuffer());
        packCounter ++;
        packData.clear();
      }

      if (!dataLen){return;}

      if (packData.getBytesFree() == 184){
        packData.clear();
        packData.setPID(pkgPid);
        packData.setContinuityCounter(++contPkg);
        if (firstPack){
          packData.setUnitStart(1);
          if (video){
            if (keyframe){
              packData.setRandomAccess(true);
              packData.setESPriority(true);
            }
            packData.setPCR(thisPacket.getTime() * 27000);
          }
          firstPack = false;
        }
      }

      int tmp = packData.fillFree(data, dataLen);
      data += tmp;
      dataLen -= tmp;
    } while(dataLen);
  }

  void TSOutput::sendNext(){
    //Get ready some data to speed up accesses
    uint32_t trackId = thisPacket.getTrackId();
    DTSC::Track & Trk = myMeta.tracks[trackId];
    bool & firstPack = first[trackId];
    uint32_t pkgPid = 255 + trackId;
    int & contPkg = contCounters[pkgPid];
    uint64_t packTime = thisPacket.getTime();
    bool video = (Trk.type == "video");
    bool keyframe = thisPacket.getInt("keyframe");
    firstPack = true;

    char * dataPointer = 0;
    unsigned int dataLen = 0;
    thisPacket.getString("data", dataPointer, dataLen); //data
    //apple compatibility timestamp correction
    if (appleCompat){
      packTime -= ts_from;
      if (Trk.type == "audio"){
        packTime = 0;
      }
    }
    packTime *= 90;
    std::string bs;
    //prepare bufferstring
    if (video){
      if (Trk.codec == "H264" || Trk.codec == "HEVC"){
        unsigned int extraSize = 0;
        //dataPointer[4] & 0x1f is used to check if this should be done later: fillPacket("\000\000\000\001\011\360", 6);
        if (Trk.codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
          extraSize += 6;
        }
        if (keyframe){
          if (Trk.codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(Trk.init);
            bs = avccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-START*/
          if (Trk.codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(Trk.init);
            bs = hvccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-END*/
        }

        unsigned int watKunnenWeIn1Ding = 65490-13;
        unsigned int splitCount = (dataLen+extraSize) / watKunnenWeIn1Ding;
        unsigned int currPack = 0;
        unsigned int ThisNaluSize = 0;
        unsigned int i = 0;
        unsigned int nalLead = 0;
        uint64_t offset = thisPacket.getInt("offset") * 90;

        while (currPack <= splitCount){
          unsigned int alreadySent = 0;
          bs = TS::Packet::getPESVideoLeadIn((currPack != splitCount ? watKunnenWeIn1Ding : dataLen+extraSize - currPack*watKunnenWeIn1Ding), packTime, offset, !currPack, Trk.bps);
          fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          if (!currPack){
            if (Trk.codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
              //End of previous nal unit, if not already present
              fillPacket("\000\000\000\001\011\360", 6, firstPack, video, keyframe, pkgPid, contPkg);
              alreadySent += 6;
            }
            if (keyframe){
              if (Trk.codec == "H264"){
                MP4::AVCC avccbox;
                avccbox.setPayload(Trk.init);
                bs = avccbox.asAnnexB();
                fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += bs.size();
              }
              /*LTS-START*/
              if (Trk.codec == "HEVC"){
                MP4::HVCC hvccbox;
                hvccbox.setPayload(Trk.init);
                bs = hvccbox.asAnnexB();
                fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += bs.size();
              }
              /*LTS-END*/
            }
          }
          while (i + 4 < (unsigned int)dataLen){
            if (nalLead){
              fillPacket("\000\000\000\001"+4-nalLead,nalLead, firstPack, video, keyframe, pkgPid, contPkg);
              i += nalLead;
              alreadySent += nalLead;
              nalLead = 0;
            }
            if (!ThisNaluSize){
              ThisNaluSize = (dataPointer[i] << 24) + (dataPointer[i+1] << 16) + (dataPointer[i+2] << 8) + dataPointer[i+3];
              if (ThisNaluSize + i + 4 > (unsigned int)dataLen){
                DEBUG_MSG(DLVL_WARN, "Too big NALU detected (%u > %d) - skipping!", ThisNaluSize + i + 4, dataLen);
                break;
              }
              if (alreadySent + 4 > watKunnenWeIn1Ding){
                nalLead = 4 - (watKunnenWeIn1Ding-alreadySent);
                fillPacket("\000\000\000\001",watKunnenWeIn1Ding-alreadySent, firstPack, video, keyframe, pkgPid, contPkg);
                i += watKunnenWeIn1Ding-alreadySent;
                alreadySent += watKunnenWeIn1Ding-alreadySent;
              }else{
                fillPacket("\000\000\000\001",4, firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += 4;
                i += 4;
              }
            }
            if (alreadySent + ThisNaluSize > watKunnenWeIn1Ding){
              fillPacket(dataPointer+i,watKunnenWeIn1Ding-alreadySent, firstPack, video, keyframe, pkgPid, contPkg);
              i += watKunnenWeIn1Ding-alreadySent;
              ThisNaluSize -= watKunnenWeIn1Ding-alreadySent;
              alreadySent += watKunnenWeIn1Ding-alreadySent;
            }else{
              fillPacket(dataPointer+i,ThisNaluSize, firstPack, video, keyframe, pkgPid, contPkg);
              alreadySent += ThisNaluSize;
              i += ThisNaluSize;
              ThisNaluSize = 0;
            }
            if (alreadySent == watKunnenWeIn1Ding){
              packData.addStuffing();
              fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
              firstPack = true;
              break;
            }
          }
          currPack++;
        }
      }else{
        uint64_t offset = thisPacket.getInt("offset") * 90;
        bs = TS::Packet::getPESVideoLeadIn(0, packTime, offset, true, Trk.bps);
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);

        fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
      }
    }else if (Trk.type == "audio"){
      long unsigned int tempLen = dataLen;
      if (Trk.codec == "AAC"){
        tempLen += 7;
      }
      bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, Trk.bps);
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      if (Trk.codec == "AAC"){
        bs = TS::getAudioHeader(dataLen, Trk.init);
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      }
      fillPacket(dataPointer,dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }
    if (packData.getBytesFree() < 184){
      packData.addStuffing();
      fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
    }
  }
}
<commit_msg>Fixed TS-output (=HLS) related SIGABRT problem<commit_after>#include "output_ts_base.h"
#include <mist/bitfields.h>

namespace Mist {
  TSOutput::TSOutput(Socket::Connection & conn) : TS_BASECLASS(conn){
    packCounter=0;
    ts_from = 0;
    setBlocking(true);
    sendRepeatingHeaders = 0;
    appleCompat=false;
    lastHeaderTime = 0;
  }

  void TSOutput::fillPacket(char const * data, size_t dataLen, bool & firstPack, bool video, bool keyframe, uint32_t pkgPid, int & contPkg){
    do {
      if (!packData.getBytesFree()){
        if ( (sendRepeatingHeaders && thisPacket.getTime() - lastHeaderTime > sendRepeatingHeaders) || !packCounter){
          lastHeaderTime = thisPacket.getTime();
          TS::Packet tmpPack;
          tmpPack.FromPointer(TS::PAT);
          tmpPack.setContinuityCounter(++contPAT);
          sendTS(tmpPack.checkAndGetBuffer());
          sendTS(TS::createPMT(selectedTracks, myMeta, ++contPMT));
          sendTS(TS::createSDT(streamName, ++contSDT));
          packCounter += 3;
        }
        sendTS(packData.checkAndGetBuffer());
        packCounter ++;
        packData.clear();
      }

      if (!dataLen){return;}

      if (packData.getBytesFree() == 184){
        packData.clear();
        packData.setPID(pkgPid);
        packData.setContinuityCounter(++contPkg);
        if (firstPack){
          packData.setUnitStart(1);
          if (video){
            if (keyframe){
              packData.setRandomAccess(true);
              packData.setESPriority(true);
            }
            packData.setPCR(thisPacket.getTime() * 27000);
          }
          firstPack = false;
        }
      }

      size_t tmp = packData.fillFree(data, dataLen);
      data += tmp;
      dataLen -= tmp;
    } while(dataLen);
  }

  void TSOutput::sendNext(){
    //Get ready some data to speed up accesses
    uint32_t trackId = thisPacket.getTrackId();
    DTSC::Track & Trk = myMeta.tracks[trackId];
    bool & firstPack = first[trackId];
    uint32_t pkgPid = 255 + trackId;
    int & contPkg = contCounters[pkgPid];
    uint64_t packTime = thisPacket.getTime();
    bool video = (Trk.type == "video");
    bool keyframe = thisPacket.getInt("keyframe");
    firstPack = true;

    char * dataPointer = 0;
    unsigned int tmpDataLen = 0;
    thisPacket.getString("data", dataPointer, tmpDataLen); //data
    uint64_t dataLen = tmpDataLen;
    //apple compatibility timestamp correction
    if (appleCompat){
      packTime -= ts_from;
      if (Trk.type == "audio"){
        packTime = 0;
      }
    }
    packTime *= 90;
    std::string bs;
    //prepare bufferstring
    if (video){
      if (Trk.codec == "H264" || Trk.codec == "HEVC"){
        unsigned int extraSize = 0;
        //dataPointer[4] & 0x1f is used to check if this should be done later: fillPacket("\000\000\000\001\011\360", 6);
        if (Trk.codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
          extraSize += 6;
        }
        if (keyframe){
          if (Trk.codec == "H264"){
            MP4::AVCC avccbox;
            avccbox.setPayload(Trk.init);
            bs = avccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-START*/
          if (Trk.codec == "HEVC"){
            MP4::HVCC hvccbox;
            hvccbox.setPayload(Trk.init);
            bs = hvccbox.asAnnexB();
            extraSize += bs.size();
          }
          /*LTS-END*/
        }

        unsigned int watKunnenWeIn1Ding = 65490-13;
        unsigned int splitCount = (dataLen+extraSize) / watKunnenWeIn1Ding;
        unsigned int currPack = 0;
        uint64_t ThisNaluSize = 0;
        unsigned int i = 0;
        unsigned int nalLead = 0;
        uint64_t offset = thisPacket.getInt("offset") * 90;

        while (currPack <= splitCount){
          unsigned int alreadySent = 0;
          bs = TS::Packet::getPESVideoLeadIn((currPack != splitCount ? watKunnenWeIn1Ding : dataLen+extraSize - currPack*watKunnenWeIn1Ding), packTime, offset, !currPack, Trk.bps);
          fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
          if (!currPack){
            if (Trk.codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
              //End of previous nal unit, if not already present
              fillPacket("\000\000\000\001\011\360", 6, firstPack, video, keyframe, pkgPid, contPkg);
              alreadySent += 6;
            }
            if (keyframe){
              if (Trk.codec == "H264"){
                MP4::AVCC avccbox;
                avccbox.setPayload(Trk.init);
                bs = avccbox.asAnnexB();
                fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += bs.size();
              }
              /*LTS-START*/
              if (Trk.codec == "HEVC"){
                MP4::HVCC hvccbox;
                hvccbox.setPayload(Trk.init);
                bs = hvccbox.asAnnexB();
                fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += bs.size();
              }
              /*LTS-END*/
            }
          }
          while (i + 4 < (unsigned int)dataLen){
            if (nalLead){
              fillPacket("\000\000\000\001"+4-nalLead,nalLead, firstPack, video, keyframe, pkgPid, contPkg);
              i += nalLead;
              alreadySent += nalLead;
              nalLead = 0;
            }
            if (!ThisNaluSize){
              ThisNaluSize = Bit::btohl(dataPointer + i);
              if (ThisNaluSize + i + 4 > dataLen){
                WARN_MSG("Too big NALU detected (%" PRIu64 " > %" PRIu64 ") - skipping!", ThisNaluSize + i + 4, dataLen);
                break;
              }
              if (alreadySent + 4 > watKunnenWeIn1Ding){
                nalLead = 4 - (watKunnenWeIn1Ding-alreadySent);
                fillPacket("\000\000\000\001",watKunnenWeIn1Ding-alreadySent, firstPack, video, keyframe, pkgPid, contPkg);
                i += watKunnenWeIn1Ding-alreadySent;
                alreadySent += watKunnenWeIn1Ding-alreadySent;
              }else{
                fillPacket("\000\000\000\001",4, firstPack, video, keyframe, pkgPid, contPkg);
                alreadySent += 4;
                i += 4;
              }
            }
            if (alreadySent + ThisNaluSize > watKunnenWeIn1Ding){
              fillPacket(dataPointer+i,watKunnenWeIn1Ding-alreadySent, firstPack, video, keyframe, pkgPid, contPkg);
              i += watKunnenWeIn1Ding-alreadySent;
              ThisNaluSize -= watKunnenWeIn1Ding-alreadySent;
              alreadySent += watKunnenWeIn1Ding-alreadySent;
            }else{
              fillPacket(dataPointer+i,ThisNaluSize, firstPack, video, keyframe, pkgPid, contPkg);
              alreadySent += ThisNaluSize;
              i += ThisNaluSize;
              ThisNaluSize = 0;
            }
            if (alreadySent == watKunnenWeIn1Ding){
              packData.addStuffing();
              fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
              firstPack = true;
              break;
            }
          }
          currPack++;
        }
      }else{
        uint64_t offset = thisPacket.getInt("offset") * 90;
        bs = TS::Packet::getPESVideoLeadIn(0, packTime, offset, true, Trk.bps);
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);

        fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
      }
    }else if (Trk.type == "audio"){
      long unsigned int tempLen = dataLen;
      if (Trk.codec == "AAC"){
        tempLen += 7;
      }
      bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, Trk.bps);
      fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      if (Trk.codec == "AAC"){
        bs = TS::getAudioHeader(dataLen, Trk.init);
        fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
      }
      fillPacket(dataPointer,dataLen, firstPack, video, keyframe, pkgPid, contPkg);
    }
    if (packData.getBytesFree() < 184){
      packData.addStuffing();
      fillPacket(0, 0, firstPack, video, keyframe, pkgPid, contPkg);
    }
  }
}
<|endoftext|>


<commit_before>#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"

#include <QDateTime>

#include <cstdlib>

// Earliest date that can be represented (far in the past)
const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0);
// Last date that can be represented (far in the future)
const QDateTime TransactionFilterProxy::MAX_DATE = QDateTime::fromTime_t(0xFFFFFFFF);

TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
    QSortFilterProxyModel(parent),
    dateFrom(MIN_DATE),
    dateTo(MAX_DATE),
    addrPrefix(),
    typeFilter(ALL_TYPES),
    minAmount(0),
    limitRows(-1)
{
}

bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
    QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);

    int type = index.data(TransactionTableModel::TypeRole).toInt();
    QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime();
    QString address = index.data(TransactionTableModel::AddressRole).toString();
    QString label = index.data(TransactionTableModel::LabelRole).toString();
    qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong());

    if(!(TYPE(type) & typeFilter))
        return false;
    if(datetime < dateFrom || datetime > dateTo)
        return false;
    if(!address.startsWith(addrPrefix) && !label.startsWith(addrPrefix))
        return false;
    if(amount < minAmount)
        return false;

    return true;
}

void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime &to)
{
    this->dateFrom = from;
    this->dateTo = to;
    invalidateFilter();
}

void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix)
{
    this->addrPrefix = addrPrefix;
    invalidateFilter();
}

void TransactionFilterProxy::setTypeFilter(quint32 modes)
{
    this->typeFilter = modes;
    invalidateFilter();
}

void TransactionFilterProxy::setMinAmount(qint64 minimum)
{
    this->minAmount = minimum;
    invalidateFilter();
}

void TransactionFilterProxy::setLimit(int limit)
{
    this->limitRows = limit;
}

int TransactionFilterProxy::rowCount(const QModelIndex &parent) const
{
    if(limitRows != -1)
    {
        return std::min(QSortFilterProxyModel::rowCount(parent), limitRows);
    }
    else
    {
        return QSortFilterProxyModel::rowCount(parent);
    }
}
<commit_msg>allow for filtering addresses and labels by searching for the typed string anywhere, not just at the beginning (#641)<commit_after>#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"

#include <QDateTime>

#include <cstdlib>

// Earliest date that can be represented (far in the past)
const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0);
// Last date that can be represented (far in the future)
const QDateTime TransactionFilterProxy::MAX_DATE = QDateTime::fromTime_t(0xFFFFFFFF);

TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
    QSortFilterProxyModel(parent),
    dateFrom(MIN_DATE),
    dateTo(MAX_DATE),
    addrPrefix(),
    typeFilter(ALL_TYPES),
    minAmount(0),
    limitRows(-1)
{
}

bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
    QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);

    int type = index.data(TransactionTableModel::TypeRole).toInt();
    QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime();
    QString address = index.data(TransactionTableModel::AddressRole).toString();
    QString label = index.data(TransactionTableModel::LabelRole).toString();
    qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong());

    if(!(TYPE(type) & typeFilter))
        return false;
    if(datetime < dateFrom || datetime > dateTo)
        return false;
    if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive))
        return false;
    if(amount < minAmount)
        return false;

    return true;
}

void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime &to)
{
    this->dateFrom = from;
    this->dateTo = to;
    invalidateFilter();
}

void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix)
{
    this->addrPrefix = addrPrefix;
    invalidateFilter();
}

void TransactionFilterProxy::setTypeFilter(quint32 modes)
{
    this->typeFilter = modes;
    invalidateFilter();
}

void TransactionFilterProxy::setMinAmount(qint64 minimum)
{
    this->minAmount = minimum;
    invalidateFilter();
}

void TransactionFilterProxy::setLimit(int limit)
{
    this->limitRows = limit;
}

int TransactionFilterProxy::rowCount(const QModelIndex &parent) const
{
    if(limitRows != -1)
    {
        return std::min(QSortFilterProxyModel::rowCount(parent), limitRows);
    }
    else
    {
        return QSortFilterProxyModel::rowCount(parent);
    }
}
<|endoftext|>


<commit_before>
/*
 * Copyright 2008 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkFontHost.h"

SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
                                     const char famillyName[],
                                     SkTypeface::Style style) {
    SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented");
    return NULL;
}

SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*) {
    SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented");
    return NULL;
}

SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) {
    SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
    return NULL;
}

// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
        uint32_t fontID,
        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
        const uint32_t* glyphIDs,
        uint32_t glyphIDsCount) {
    SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
    return NULL;
}

void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
}

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

SkStream* SkFontHost::OpenStream(uint32_t uniqueID) {
    SkDEBUGFAIL("SkFontHost::OpenStream unimplemented");
    return NULL;
}

size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
                               int32_t* index) {
    SkDebugf("SkFontHost::GetFileName unimplemented\n");
    return 0;
}

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

void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
    SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
}

SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
    return NULL;
}

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

SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
    SkDEBUGFAIL("SkFontHost::CreateScalarContext unimplemented");
    return NULL;
}

SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
    return 0;
}

<commit_msg>Fix compile error in SkFontHost_none.cpp Review URL: https://codereview.appspot.com/6501083<commit_after>
/*
 * Copyright 2008 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkFontHost.h"
#include "SkScalerContext.h"

SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
                                     const char famillyName[],
                                     SkTypeface::Style style) {
    SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented");
    return NULL;
}

SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*) {
    SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented");
    return NULL;
}

SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) {
    SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
    return NULL;
}

// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
        uint32_t fontID,
        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
        const uint32_t* glyphIDs,
        uint32_t glyphIDsCount) {
    SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
    return NULL;
}

void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
}

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

SkStream* SkFontHost::OpenStream(uint32_t uniqueID) {
    SkDEBUGFAIL("SkFontHost::OpenStream unimplemented");
    return NULL;
}

size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
                               int32_t* index) {
    SkDebugf("SkFontHost::GetFileName unimplemented\n");
    return 0;
}

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

void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
    SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
}

SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
    return NULL;
}

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

SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
    SkDEBUGFAIL("SkFontHost::CreateScalarContext unimplemented");
    return NULL;
}

SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
    return 0;
}

<|endoftext|>


<commit_before>#ifndef RENHOOK_HOOKS_INLINE_HOOK_H
#define RENHOOK_HOOKS_INLINE_HOOK_H

#include <string>
#include <Windows.h>

#include <renhook/exception.hpp>
#include <renhook/executable.hpp>
#include <renhook/hook_writer.hpp>
#include <renhook/pattern.hpp>
#include <renhook/suspend_threads.hpp>
#include <renhook/zydis.hpp>

#include <renhook/memory/memory_allocator.hpp>
#include <renhook/memory/virtual_protect.hpp>

namespace renhook
{
    /**
     * @brief An inline hook.
     *
     * @tparam T The hooked function type.
     */
    template<typename T>
    class inline_hook
    {
    public:

        /**
         * @brief Construct an empty hook.
         */
        inline_hook()
            : m_target_address(0)
            , m_detour_address(0)
            , m_wildcard(0)
            , m_offset(0)
            , m_attached(false)
            , m_decoded_length(0)
            , m_block(nullptr)
        {
        }

        /**
         * @brief Construct a new hook.
         *
         * @param target_address[in] The address of the function that will be hooked.
         * @param detour_address[in] The address of the callback.
         */
        inline_hook(uintptr_t target_address, uintptr_t detour_address)
            : inline_hook()
        {
            m_target_address = target_address;
            m_detour_address = detour_address;
        }

        /**
         * @brief Construct a new hook.
         *
         * @param target_address[in] The address of the function that will be hooked.
         * @param detour_address[in] The address of the callback.
         */
        inline_hook(uintptr_t target_address, T detour_address)
            : inline_hook(target_address, reinterpret_cast<uintptr_t>(detour_address))
        {
        }

        /**
         * @brief Construct a new hook using a pattern.
         *
         * @param pattern[in]           The pattern of the function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         * @param wildcard[in]          The wildcard for #pattern.
         * @param offset[in]            The offset of the #pattern.
         */
        inline_hook(pattern pattern, uintptr_t detour_address, uint8_t wildcard = 0xCC, size_t offset = 0)
            : inline_hook()
        {
            m_detour_address = detour_address;
            m_pattern = std::move(pattern);
            m_wildcard = wildcard;
            m_offset = offset;
        }

        /**
         * @brief Construct a new hook using a pattern.
         *
         * @param pattern[in]           The pattern of the function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         * @param wildcard[in]          The wildcard for #pattern.
         * @param offset[in]            The offset of the #pattern.
         */
        inline_hook(pattern pattern, T detour_address, uint8_t wildcard = 0xCC, size_t offset = 0)
            : inline_hook(pattern, reinterpret_cast<uintptr_t>(detour_address), wildcard, offset)
        {
        }

        /**
         * @brief Construct a new hook.
         *
         * @param module[in]            The module which contain the #function.
         * @param function[in]          The function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         *
         * @note If the module is not loaded, the library will load it when the hook is attached.
         */
        inline_hook(const std::string& module, const std::string& function, uintptr_t detour_address)
            : inline_hook()
        {
            m_module = module;
            m_function = function;
        }

        /**
         * @brief Construct a new hook.
         *
         * @param module[in]            The module which contain the #function.
         * @param function[in]          The function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         *
         * @note If the module is not loaded, the library will load it when the hook is attached.
         */
        inline_hook(const std::string& module, const std::string& function, T detour_address)
            : inline_hook(module, function, reinterpret_cast<uintptr_t>(detour_address))
        {
        }

        inline_hook(inline_hook&& rhs) noexcept
            : m_target_address(rhs.m_target_address)
            , m_detour_address(rhs.m_detour_address)
            , m_pattern(std::move(rhs.m_pattern))
            , m_wildcard(rhs.m_wildcard)
            , m_offset(rhs.m_offset)
            , m_attached(rhs.m_attached)
            , m_decoded_length(rhs.m_decoded_length)
            , m_block(rhs.m_block)
        {
            rhs.m_attached = false;
            rhs.m_block = nullptr;
        }

        ~inline_hook()
        {
            detach();
        }

        inline_hook& operator=(inline_hook&& rhs) noexcept
        {
            m_target_address = rhs.m_target_address;
            m_detour_address = rhs.m_detour_address;
            m_pattern = std::move(rhs.m_pattern);
            m_wildcard = rhs.m_wildcard;
            m_offset = rhs.m_offset;
            m_attached = rhs.m_attached;
            m_decoded_length = rhs.m_decoded_length;
            m_block = rhs.m_block;

            rhs.m_attached = false;
            rhs.m_block = nullptr;

            return *this;
        }

        inline_hook(inline_hook&) = delete;
        inline_hook& operator=(const inline_hook&) = delete;

        /**
         * @brief Call the original function.
         *
         * @return The value returned by the original function.
         */
        operator T() const
        {
            return reinterpret_cast<T>(m_block);
        }

        /**
         * @brief Enable the hook.
         */
        void attach()
        {
            using namespace renhook::memory;

            if (m_attached)
            {
                return;
            }

            if (!m_module.empty())
            {
                auto module_handle = GetModuleHandleA(m_module.c_str());
                if (!module_handle)
                {
                    LoadLibraryA(m_module.c_str());

                    module_handle = GetModuleHandleA(m_module.c_str());
                    if (!module_handle)
                    {
                        throw renhook::exception("module not found");
                    }
                }

                m_target_address = reinterpret_cast<uintptr_t>(GetProcAddress(module_handle, m_function.c_str()));
                if (m_target_address == 0)
                {
                    throw renhook::exception("cannot find function in module");
                }
            }

            if (m_target_address == 0)
            {
                if (m_pattern.empty())
                {
                    throw renhook::exception("cannot attach an empty hook");
                }

                auto addresses = m_pattern.find(m_wildcard);
                m_target_address = addresses.at(m_offset);
            }

            m_target_address = skip_jumps(m_target_address);
            m_detour_address = skip_jumps(m_detour_address);

            renhook::zydis zydis;
            auto instructions = zydis.decode(m_target_address, executable::get_code_size(), hook_size, m_decoded_length);

            suspend_threads threads(m_target_address, m_decoded_length);

            extern memory_allocator global_allocator;
            m_block = static_cast<uint8_t*>(global_allocator.alloc());

            // Write the bytes to our memory.
            virtual_protect block_protection(m_block, memory_allocator::block_size, protection::read | protection::write | protection::execute);
            hook_writer block_writer(m_block);

            block_writer.copy_from(m_target_address, m_decoded_length);
            block_writer.write_jump(m_target_address + m_decoded_length);

            relocate_instructions(instructions, &block_writer);

            // Write the jump in the original function.
            virtual_protect func_protection(m_target_address, m_decoded_length, protection::read | protection::write | protection::execute);
            hook_writer func_writer(m_target_address);

            func_writer.write_jump(m_detour_address);
            func_writer.write_nops(m_decoded_length - hook_size);

            flush_cache();
            m_attached = true;
        }

        /**
         * @brief Disable the hook.
         */
        void detach()
        {
            using namespace renhook::memory;

            if (!m_attached)
            {
                return;
            }

            suspend_threads threads(m_target_address, m_decoded_length);
            virtual_protect func_protection(m_target_address, m_decoded_length, protection::read | protection::write | protection::execute);

            hook_writer func_writer(m_target_address);
            func_writer.copy_from(m_block, m_decoded_length);

            renhook::zydis zydis;
            auto instructions = zydis.decode(reinterpret_cast<uintptr_t>(m_block), executable::get_code_size(), m_decoded_length, m_decoded_length);

            relocate_instructions(instructions, nullptr);

            extern memory_allocator global_allocator;
            global_allocator.free(m_block);

            m_block = nullptr;

            flush_cache();
            m_attached = false;
        }

    protected:

        /**
         * @brief Get the block address.
         *
         * @return The block address.
         *
         * @note This is only used in tests.
         */
        const uint8_t* get_block_address() const
        {
            return m_block;
        }

    private:

        /**
         * @brief The size of the hook.
         */
#ifdef _WIN64
        static constexpr size_t hook_size = 14;
#else
        static constexpr size_t hook_size = 5;
#endif

        /**
         * @brief Check if the first instruction is a jump, if it is follow it until the real address of the function is found.
         *
         * @param address[in] The address to check.
         *
         * @return The real function's address.
         */
        uintptr_t skip_jumps(uintptr_t address) const
        {
            if (address == 0)
            {
                return 0;
            }

            auto memory = reinterpret_cast<uint8_t*>(address);
            if (memory[0] == 0xEB)
            {
                // We have a 8-bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 2 + *reinterpret_cast<int8_t*>(&memory[1]));
                return skip_jumps(address);
            }
            else if (memory[0] == 0xE9)
            {
                // We have a 32-bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 5 + *reinterpret_cast<int32_t*>(&memory[1]));
                return skip_jumps(address);
            }
            else if (memory[0] == 0xFF && memory[1] == 0x25)
            {
#ifdef _WIN64
                // We have a 32bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 6 + *reinterpret_cast<int32_t*>(&memory[2]));
#else
                // We have an absolute pointer.
                address = *reinterpret_cast<uintptr_t*>(&memory[2]);
#endif

                return skip_jumps(address);
            }
#ifdef _WIN64
            else if (memory[0] == 0x48 && memory[1] == 0xFF && memory[2] == 0x25)
            {
                // We have a 32bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 7 + *reinterpret_cast<int32_t*>(&memory[3]));
                return skip_jumps(address);
            }
#endif

            return address;
        }

        /**
         * @brief Relocate all EIP / RIP instructions.
         *
         * @param instructions[in] An array of decoded instructions.
         * @param block_writer[in] The writer of the block (only necessary if the hook is attached).
         */
        void relocate_instructions(std::vector<zydis::instruction>& instructions, hook_writer* block_writer)
        {
            auto instr_address = m_attached ? m_target_address : reinterpret_cast<uintptr_t>(m_block);
            size_t index = 0;

            for (auto& instr : instructions)
            {
                // Check if it is a conditional jump.
                if (instr.is_relative &&
                    ((instr.decoded.opcode & 0xF0) == 0x70 ||
                     (instr.decoded.opcode_map == ZYDIS_OPCODE_MAP_0F && (instr.decoded.opcode & 0xF0) == 0x80) ||
                      instr.decoded.mnemonic == ZYDIS_MNEMONIC_CALL))
                {
                    // Calculate where the displacement is in instruction.
                    auto disp_address = instr_address + instr.disp.offset;

#ifdef _WIN64
                    constexpr size_t jmp_size = 14;
                    constexpr size_t jmp_instr_size = 6;
#else
                    constexpr size_t jmp_size = 5;
                    constexpr size_t jmp_instr_size = 1;
#endif

                    auto table_address = m_block + m_decoded_length + hook_size;

                    // The address of the jump instruction in jump table for the current instruction.
                    auto jmp_instr_address = table_address + (jmp_size * index);

                    // Create a jump table if it is not attached, else get the real address from jump table.
                    if (!m_attached)
                    {
                        block_writer->write_jump(instr.disp.absolute_address);
                        instr.disp.absolute_address = reinterpret_cast<uintptr_t>(jmp_instr_address);
                    }
                    else
                    {
                        instr.disp.absolute_address = *reinterpret_cast<uintptr_t*>(jmp_instr_address + jmp_instr_size);

#ifndef _WIN64
                        // On x86 we have a displacement instead of absolute address.
                        instr.disp.absolute_address += reinterpret_cast<uintptr_t>(jmp_instr_address) + jmp_size;
#endif
                    }

                    switch (instr.disp.size)
                    {
                        case 8:
                        {
                            *reinterpret_cast<int8_t*>(disp_address) = static_cast<int8_t>(utils::calculate_displacement(instr_address, instr.disp.absolute_address, instr.decoded.length));
                            break;
                        }
                        case 16:
                        {
                            *reinterpret_cast<int16_t*>(disp_address) = static_cast<int16_t>(utils::calculate_displacement(instr_address, instr.disp.absolute_address, instr.decoded.length));
                            break;
                        }
                        case 32:
                        {
                            *reinterpret_cast<int32_t*>(disp_address) = static_cast<int32_t>(utils::calculate_displacement(instr_address, instr.disp.absolute_address, instr.decoded.length));
                            break;
                        }
                    }

                    index++;
                }

                instr_address += instr.decoded.length;
            }
        }

        /**
         * @brief Flush instruction cache for the original function and for the codecave.
         */
        void flush_cache() const
        {
            auto current_process = GetCurrentProcess();

            FlushInstructionCache(current_process, m_block, memory::memory_allocator::block_size);
            FlushInstructionCache(current_process, reinterpret_cast<void*>(m_target_address), m_decoded_length);
        }

        uintptr_t m_target_address;
        uintptr_t m_detour_address;

        pattern m_pattern;
        uint8_t m_wildcard;
        size_t m_offset;

        std::string m_module;
        std::string m_function;

        bool m_attached;

        size_t m_decoded_length;
        uint8_t* m_block;
    };
}
#endif
<commit_msg>Fix build error and set detour address when calling a constructor with a module<commit_after>#ifndef RENHOOK_HOOKS_INLINE_HOOK_H
#define RENHOOK_HOOKS_INLINE_HOOK_H

#include <string>
#include <Windows.h>

#include <renhook/exception.hpp>
#include <renhook/executable.hpp>
#include <renhook/hook_writer.hpp>
#include <renhook/pattern.hpp>
#include <renhook/suspend_threads.hpp>
#include <renhook/utils.hpp>
#include <renhook/zydis.hpp>

#include <renhook/memory/memory_allocator.hpp>
#include <renhook/memory/virtual_protect.hpp>

namespace renhook
{
    /**
     * @brief An inline hook.
     *
     * @tparam T The hooked function type.
     */
    template<typename T>
    class inline_hook
    {
    public:

        /**
         * @brief Construct an empty hook.
         */
        inline_hook()
            : m_target_address(0)
            , m_detour_address(0)
            , m_wildcard(0)
            , m_offset(0)
            , m_attached(false)
            , m_decoded_length(0)
            , m_block(nullptr)
        {
        }

        /**
         * @brief Construct a new hook.
         *
         * @param target_address[in] The address of the function that will be hooked.
         * @param detour_address[in] The address of the callback.
         */
        inline_hook(uintptr_t target_address, uintptr_t detour_address)
            : inline_hook()
        {
            m_target_address = target_address;
            m_detour_address = detour_address;
        }

        /**
         * @brief Construct a new hook.
         *
         * @param target_address[in] The address of the function that will be hooked.
         * @param detour_address[in] The address of the callback.
         */
        inline_hook(uintptr_t target_address, T detour_address)
            : inline_hook(target_address, reinterpret_cast<uintptr_t>(detour_address))
        {
        }

        /**
         * @brief Construct a new hook using a pattern.
         *
         * @param pattern[in]           The pattern of the function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         * @param wildcard[in]          The wildcard for #pattern.
         * @param offset[in]            The offset of the #pattern.
         */
        inline_hook(pattern pattern, uintptr_t detour_address, uint8_t wildcard = 0xCC, size_t offset = 0)
            : inline_hook()
        {
            m_detour_address = detour_address;
            m_pattern = std::move(pattern);
            m_wildcard = wildcard;
            m_offset = offset;
        }

        /**
         * @brief Construct a new hook using a pattern.
         *
         * @param pattern[in]           The pattern of the function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         * @param wildcard[in]          The wildcard for #pattern.
         * @param offset[in]            The offset of the #pattern.
         */
        inline_hook(pattern pattern, T detour_address, uint8_t wildcard = 0xCC, size_t offset = 0)
            : inline_hook(pattern, reinterpret_cast<uintptr_t>(detour_address), wildcard, offset)
        {
        }

        /**
         * @brief Construct a new hook.
         *
         * @param module[in]            The module which contain the #function.
         * @param function[in]          The function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         *
         * @note If the module is not loaded, the library will load it when the hook is attached.
         */
        inline_hook(const std::string& module, const std::string& function, uintptr_t detour_address)
            : inline_hook()
        {
            m_module = module;
            m_function = function;
            m_detour_address = detour_address;
        }

        /**
         * @brief Construct a new hook.
         *
         * @param module[in]            The module which contain the #function.
         * @param function[in]          The function that will be hooked.
         * @param detour_address[in]    The address of the callback.
         *
         * @note If the module is not loaded, the library will load it when the hook is attached.
         */
        inline_hook(const std::string& module, const std::string& function, T detour_address)
            : inline_hook(module, function, reinterpret_cast<uintptr_t>(detour_address))
        {
        }

        inline_hook(inline_hook&& rhs) noexcept
            : m_target_address(rhs.m_target_address)
            , m_detour_address(rhs.m_detour_address)
            , m_pattern(std::move(rhs.m_pattern))
            , m_wildcard(rhs.m_wildcard)
            , m_offset(rhs.m_offset)
            , m_attached(rhs.m_attached)
            , m_decoded_length(rhs.m_decoded_length)
            , m_block(rhs.m_block)
        {
            rhs.m_attached = false;
            rhs.m_block = nullptr;
        }

        ~inline_hook()
        {
            detach();
        }

        inline_hook& operator=(inline_hook&& rhs) noexcept
        {
            m_target_address = rhs.m_target_address;
            m_detour_address = rhs.m_detour_address;
            m_pattern = std::move(rhs.m_pattern);
            m_wildcard = rhs.m_wildcard;
            m_offset = rhs.m_offset;
            m_attached = rhs.m_attached;
            m_decoded_length = rhs.m_decoded_length;
            m_block = rhs.m_block;

            rhs.m_attached = false;
            rhs.m_block = nullptr;

            return *this;
        }

        inline_hook(inline_hook&) = delete;
        inline_hook& operator=(const inline_hook&) = delete;

        /**
         * @brief Call the original function.
         *
         * @return The value returned by the original function.
         */
        operator T() const
        {
            return reinterpret_cast<T>(m_block);
        }

        /**
         * @brief Enable the hook.
         */
        void attach()
        {
            using namespace renhook::memory;

            if (m_attached)
            {
                return;
            }

            if (!m_module.empty())
            {
                auto module_handle = GetModuleHandleA(m_module.c_str());
                if (!module_handle)
                {
                    LoadLibraryA(m_module.c_str());

                    module_handle = GetModuleHandleA(m_module.c_str());
                    if (!module_handle)
                    {
                        throw renhook::exception("module not found");
                    }
                }

                m_target_address = reinterpret_cast<uintptr_t>(GetProcAddress(module_handle, m_function.c_str()));
                if (m_target_address == 0)
                {
                    throw renhook::exception("cannot find function in module");
                }
            }

            if (m_target_address == 0)
            {
                if (m_pattern.empty())
                {
                    throw renhook::exception("cannot attach an empty hook");
                }

                auto addresses = m_pattern.find(m_wildcard);
                m_target_address = addresses.at(m_offset);
            }

            m_target_address = skip_jumps(m_target_address);
            m_detour_address = skip_jumps(m_detour_address);

            renhook::zydis zydis;
            auto instructions = zydis.decode(m_target_address, executable::get_code_size(), hook_size, m_decoded_length);

            suspend_threads threads(m_target_address, m_decoded_length);

            extern memory_allocator global_allocator;
            m_block = static_cast<uint8_t*>(global_allocator.alloc());

            // Write the bytes to our memory.
            virtual_protect block_protection(m_block, memory_allocator::block_size, protection::read | protection::write | protection::execute);
            hook_writer block_writer(m_block);

            block_writer.copy_from(m_target_address, m_decoded_length);
            block_writer.write_jump(m_target_address + m_decoded_length);

            relocate_instructions(instructions, &block_writer);

            // Write the jump in the original function.
            virtual_protect func_protection(m_target_address, m_decoded_length, protection::read | protection::write | protection::execute);
            hook_writer func_writer(m_target_address);

            func_writer.write_jump(m_detour_address);
            func_writer.write_nops(m_decoded_length - hook_size);

            flush_cache();
            m_attached = true;
        }

        /**
         * @brief Disable the hook.
         */
        void detach()
        {
            using namespace renhook::memory;

            if (!m_attached)
            {
                return;
            }

            suspend_threads threads(m_target_address, m_decoded_length);
            virtual_protect func_protection(m_target_address, m_decoded_length, protection::read | protection::write | protection::execute);

            hook_writer func_writer(m_target_address);
            func_writer.copy_from(m_block, m_decoded_length);

            renhook::zydis zydis;
            auto instructions = zydis.decode(reinterpret_cast<uintptr_t>(m_block), executable::get_code_size(), m_decoded_length, m_decoded_length);

            relocate_instructions(instructions, nullptr);

            extern memory_allocator global_allocator;
            global_allocator.free(m_block);

            m_block = nullptr;

            flush_cache();
            m_attached = false;
        }

    protected:

        /**
         * @brief Get the block address.
         *
         * @return The block address.
         *
         * @note This is only used in tests.
         */
        const uint8_t* get_block_address() const
        {
            return m_block;
        }

    private:

        /**
         * @brief The size of the hook.
         */
#ifdef _WIN64
        static constexpr size_t hook_size = 14;
#else
        static constexpr size_t hook_size = 5;
#endif

        /**
         * @brief Check if the first instruction is a jump, if it is follow it until the real address of the function is found.
         *
         * @param address[in] The address to check.
         *
         * @return The real function's address.
         */
        uintptr_t skip_jumps(uintptr_t address) const
        {
            if (address == 0)
            {
                return 0;
            }

            auto memory = reinterpret_cast<uint8_t*>(address);
            if (memory[0] == 0xEB)
            {
                // We have a 8-bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 2 + *reinterpret_cast<int8_t*>(&memory[1]));
                return skip_jumps(address);
            }
            else if (memory[0] == 0xE9)
            {
                // We have a 32-bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 5 + *reinterpret_cast<int32_t*>(&memory[1]));
                return skip_jumps(address);
            }
            else if (memory[0] == 0xFF && memory[1] == 0x25)
            {
#ifdef _WIN64
                // We have a 32bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 6 + *reinterpret_cast<int32_t*>(&memory[2]));
#else
                // We have an absolute pointer.
                address = *reinterpret_cast<uintptr_t*>(&memory[2]);
#endif

                return skip_jumps(address);
            }
#ifdef _WIN64
            else if (memory[0] == 0x48 && memory[1] == 0xFF && memory[2] == 0x25)
            {
                // We have a 32bit offset to the target.
                address = reinterpret_cast<uintptr_t>(memory + 7 + *reinterpret_cast<int32_t*>(&memory[3]));
                return skip_jumps(address);
            }
#endif

            return address;
        }

        /**
         * @brief Relocate all EIP / RIP instructions.
         *
         * @param instructions[in] An array of decoded instructions.
         * @param block_writer[in] The writer of the block (only necessary if the hook is attached).
         */
        void relocate_instructions(std::vector<zydis::instruction>& instructions, hook_writer* block_writer)
        {
            auto instr_address = m_attached ? m_target_address : reinterpret_cast<uintptr_t>(m_block);
            size_t index = 0;

            for (auto& instr : instructions)
            {
                // Check if it is a conditional jump.
                if (instr.is_relative &&
                    ((instr.decoded.opcode & 0xF0) == 0x70 ||
                     (instr.decoded.opcode_map == ZYDIS_OPCODE_MAP_0F && (instr.decoded.opcode & 0xF0) == 0x80) ||
                      instr.decoded.mnemonic == ZYDIS_MNEMONIC_CALL))
                {
                    // Calculate where the displacement is in instruction.
                    auto disp_address = instr_address + instr.disp.offset;

#ifdef _WIN64
                    constexpr size_t jmp_size = 14;
                    constexpr size_t jmp_instr_size = 6;
#else
                    constexpr size_t jmp_size = 5;
                    constexpr size_t jmp_instr_size = 1;
#endif

                    auto table_address = m_block + m_decoded_length + hook_size;

                    // The address of the jump instruction in jump table for the current instruction.
                    auto jmp_instr_address = table_address + (jmp_size * index);

                    // Create a jump table if it is not attached, else get the real address from jump table.
                    if (!m_attached)
                    {
                        block_writer->write_jump(instr.disp.absolute_address);
                        instr.disp.absolute_address = reinterpret_cast<uintptr_t>(jmp_instr_address);
                    }
                    else
                    {
                        instr.disp.absolute_address = *reinterpret_cast<uintptr_t*>(jmp_instr_address + jmp_instr_size);

#ifndef _WIN64
                        // On x86 we have a displacement instead of absolute address.
                        instr.disp.absolute_address += reinterpret_cast<uintptr_t>(jmp_instr_address) + jmp_size;
#endif
                    }

                    switch (instr.disp.size)
                    {
                        case 8:
                        {
                            *reinterpret_cast<int8_t*>(disp_address) = static_cast<int8_t>(utils::calculate_displacement(instr_address, instr.disp.absolute_address, instr.decoded.length));
                            break;
                        }
                        case 16:
                        {
                            *reinterpret_cast<int16_t*>(disp_address) = static_cast<int16_t>(utils::calculate_displacement(instr_address, instr.disp.absolute_address, instr.decoded.length));
                            break;
                        }
                        case 32:
                        {
                            *reinterpret_cast<int32_t*>(disp_address) = static_cast<int32_t>(utils::calculate_displacement(instr_address, instr.disp.absolute_address, instr.decoded.length));
                            break;
                        }
                    }

                    index++;
                }

                instr_address += instr.decoded.length;
            }
        }

        /**
         * @brief Flush instruction cache for the original function and for the codecave.
         */
        void flush_cache() const
        {
            auto current_process = GetCurrentProcess();

            FlushInstructionCache(current_process, m_block, memory::memory_allocator::block_size);
            FlushInstructionCache(current_process, reinterpret_cast<void*>(m_target_address), m_decoded_length);
        }

        uintptr_t m_target_address;
        uintptr_t m_detour_address;

        pattern m_pattern;
        uint8_t m_wildcard;
        size_t m_offset;

        std::string m_module;
        std::string m_function;

        bool m_attached;

        size_t m_decoded_length;
        uint8_t* m_block;
    };
}
#endif
<|endoftext|>


<commit_before>#include "ros2_simple_logger/Logger.h"

simpleLogger* simpleLogger::instance = NULL;

std::mutex simpleLogger::globalLogger_mutex;

void simpleLogger::initLogger(rclcpp::node::Node::SharedPtr _node)
{
    std::lock_guard<std::mutex> lock(globalLogger_mutex);
    this->publisher = _node->create_publisher<ros2_simple_logger::msg::LoggingMessage>("ros2_log", rmw_qos_profile_sensor_data);
}

simpleLogger *simpleLogger::getInstance()
{
    //TODO check if a static local instance would be better
    if(instance == NULL)
        instance = new simpleLogger();
    return instance;
}

simpleLogger::~simpleLogger()
{
    //Close the file writer
    logFileWriter.close();
}

void simpleLogger::setLogLevel(LogLevel level)
{
    messageLogLevel = level;
    printLogLevel = level;
}

void simpleLogger::setLogFilePath(std::__cxx11::string path)
{
    if(path != "" && logFileWriter.is_open())
        logFileWriter.close();
    //Check if the filename already exists
    if(check_if_file_exists(path))
    {
         int result = 0;
        //Backup logfile already exists
        if(check_if_file_exists(path+".1"))
        {
            //Remove it
            result = remove((path+".1").c_str());
            if(result != 0)
                 throw std::runtime_error("Can't remove old logfile "+ path + ".1");

        }
        //Yes move the file to path.1

        result = rename (path.c_str(), (path+".1").c_str());
        if(result != 0)
            throw std::runtime_error("Can't move old logfile to "+ path + ".1");
    }

    //Open the logfile
    logFileWriter.open(path);
    //Check if we could open it
    if(!logFileWriter.is_open())
        throw std::runtime_error("Can't open logfile: " + path);
    logFilePath = path;
}

simpleLogger &simpleLogger::getStream(LogLevel level)
{
    if(level != currentLogLevel)
        log_stream<<'\n';
    currentLogLevel = level;
    //Return this as stream
    return *this;
}

void simpleLogger::set_now(builtin_interfaces::msg::Time &time)
{
    //See ros2 demos for more information
    std::chrono::nanoseconds now = std::chrono::high_resolution_clock::now().time_since_epoch();
    if (now <= std::chrono::nanoseconds(0)) {
        time.sec = time.nanosec = 0;
    } else {
        time.sec = static_cast<builtin_interfaces::msg::Time::_sec_type>(now.count() / 1000000000);
        time.nanosec = now.count() % 1000000000;
    }
}

simpleLogger::simpleLogger():std::ostream(this)
{

}

int simpleLogger::overflow(int c)
{
    if(c == EOF)
        return c;
    if(c == '\n')
    {
        //Some thread safety - not perfect
        std::lock_guard<std::mutex> lock(globalLogger_mutex);

        if(log_stream.str() == "")
            return c;

        //Prepare ros message
        //builtin_interfaces::msg::Time time;
        set_now(time);
        //msg->level = level;
        //msg->stamp = time;

        //Get time
        auto now = std::chrono::system_clock::now();
        auto in_time_t = std::chrono::system_clock::to_time_t(now);

        //Generate loglevel output
        std::string levelStr = "";
        switch(currentLogLevel)
        {
        case Debug:
            levelStr = printInColor("Debug  : ", ConsoleColor::FG_BLUE);
            break;
        case Info:
            levelStr = printInColor("Info   : ", ConsoleColor::FG_GREEN);
            break;
        case Important:
            levelStr = printInColor("Important: ", ConsoleColor::FG_WHITE, ConsoleColor::BG_GREEN);
            break;
        case Warning:
            levelStr = printInColor("Warning: ", ConsoleColor::FG_RED);
            break;
        case Error:
            levelStr = printInColor("Error  : ", ConsoleColor::FG_RED, ConsoleColor::BG_YELLOW);
            break;
        case Fatal:
            levelStr = printInColor("Fatal  : ", ConsoleColor::FG_RED, ConsoleColor::BG_WHITE);
            break;
        }
        std::ostringstream timeStrStream;
        //Write preset into log_stream
    #if __GNUC__ >= 5
        timeStrStream << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X") << " : ";
    #else
        timeStrStream << ctime (&in_time_t) << " : " ;
    #endif

        if(printLogLevel <= currentLogLevel)
            std::cout << timeStrStream.str() << levelStr << log_stream.str()  << std::endl;
        if(fileLogLevel <= currentLogLevel && logFileWriter.is_open())
            logFileWriter << timeStrStream.str() << levelStr << log_stream.str() << '\n';
        if(messageLogLevel <= currentLogLevel && publisher != NULL){
            auto msg = std::make_shared<ros2_simple_logger::msg::LoggingMessage>();
            msg->stamp = time;
            msg->level = messageLogLevel;
            msg->message = log_stream.str();
            publisher->publish(msg);
        }
        log_stream.str("");
    }
    else
    {
        log_stream << (char)c;
    }
    return c;
}

bool simpleLogger::check_if_file_exists(const std::__cxx11::string filename)
{
    std::ifstream file(filename);
    return file.good();
}
<commit_msg>No new line when switching loglevel<commit_after>#include "ros2_simple_logger/Logger.h"

simpleLogger* simpleLogger::instance = NULL;

std::mutex simpleLogger::globalLogger_mutex;

void simpleLogger::initLogger(rclcpp::node::Node::SharedPtr _node)
{
    std::lock_guard<std::mutex> lock(globalLogger_mutex);
    this->publisher = _node->create_publisher<ros2_simple_logger::msg::LoggingMessage>("ros2_log", rmw_qos_profile_sensor_data);
}

simpleLogger *simpleLogger::getInstance()
{
    //TODO check if a static local instance would be better
    if(instance == NULL)
        instance = new simpleLogger();
    return instance;
}

simpleLogger::~simpleLogger()
{
    //Close the file writer
    logFileWriter.close();
}

void simpleLogger::setLogLevel(LogLevel level)
{
    messageLogLevel = level;
    printLogLevel = level;
}

void simpleLogger::setLogFilePath(std::__cxx11::string path)
{
    if(path != "" && logFileWriter.is_open())
        logFileWriter.close();
    //Check if the filename already exists
    if(check_if_file_exists(path))
    {
         int result = 0;
        //Backup logfile already exists
        if(check_if_file_exists(path+".1"))
        {
            //Remove it
            result = remove((path+".1").c_str());
            if(result != 0)
                 throw std::runtime_error("Can't remove old logfile "+ path + ".1");

        }
        //Yes move the file to path.1

        result = rename (path.c_str(), (path+".1").c_str());
        if(result != 0)
            throw std::runtime_error("Can't move old logfile to "+ path + ".1");
    }

    //Open the logfile
    logFileWriter.open(path);
    //Check if we could open it
    if(!logFileWriter.is_open())
        throw std::runtime_error("Can't open logfile: " + path);
    logFilePath = path;
}

simpleLogger &simpleLogger::getStream(LogLevel level)
{
    if(level != currentLogLevel)
        *this<<'\n';
    currentLogLevel = level;
    //Return this as stream
    return *this;
}

void simpleLogger::set_now(builtin_interfaces::msg::Time &time)
{
    //See ros2 demos for more information
    std::chrono::nanoseconds now = std::chrono::high_resolution_clock::now().time_since_epoch();
    if (now <= std::chrono::nanoseconds(0)) {
        time.sec = time.nanosec = 0;
    } else {
        time.sec = static_cast<builtin_interfaces::msg::Time::_sec_type>(now.count() / 1000000000);
        time.nanosec = now.count() % 1000000000;
    }
}

simpleLogger::simpleLogger():std::ostream(this)
{

}

int simpleLogger::overflow(int c)
{
    if(c == EOF)
        return c;
    if(c == '\n')
    {
        //Some thread safety - not perfect
        std::lock_guard<std::mutex> lock(globalLogger_mutex);

        if(log_stream.str() == "")
            return c;

        //Prepare ros message
        //builtin_interfaces::msg::Time time;
        set_now(time);
        //msg->level = level;
        //msg->stamp = time;

        //Get time
        auto now = std::chrono::system_clock::now();
        auto in_time_t = std::chrono::system_clock::to_time_t(now);

        //Generate loglevel output
        std::string levelStr = "";
        switch(currentLogLevel)
        {
        case Debug:
            levelStr = printInColor("Debug  : ", ConsoleColor::FG_BLUE);
            break;
        case Info:
            levelStr = printInColor("Info   : ", ConsoleColor::FG_GREEN);
            break;
        case Important:
            levelStr = printInColor("Important: ", ConsoleColor::FG_WHITE, ConsoleColor::BG_GREEN);
            break;
        case Warning:
            levelStr = printInColor("Warning: ", ConsoleColor::FG_RED);
            break;
        case Error:
            levelStr = printInColor("Error  : ", ConsoleColor::FG_RED, ConsoleColor::BG_YELLOW);
            break;
        case Fatal:
            levelStr = printInColor("Fatal  : ", ConsoleColor::FG_RED, ConsoleColor::BG_WHITE);
            break;
        }
        std::ostringstream timeStrStream;
        //Write preset into log_stream
    #if __GNUC__ >= 5
        timeStrStream << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X") << " : ";
    #else
        timeStrStream << ctime (&in_time_t) << " : " ;
    #endif

        if(printLogLevel <= currentLogLevel)
            std::cout << timeStrStream.str() << levelStr << log_stream.str()  << std::endl;
        if(fileLogLevel <= currentLogLevel && logFileWriter.is_open())
            logFileWriter << timeStrStream.str() << levelStr << log_stream.str() << '\n';
        if(messageLogLevel <= currentLogLevel && publisher != NULL){
            auto msg = std::make_shared<ros2_simple_logger::msg::LoggingMessage>();
            msg->stamp = time;
            msg->level = messageLogLevel;
            msg->message = log_stream.str();
            publisher->publish(msg);
        }
        log_stream.str("");
    }
    else
    {
        log_stream << (char)c;
    }
    return c;
}

bool simpleLogger::check_if_file_exists(const std::__cxx11::string filename)
{
    std::ifstream file(filename);
    return file.good();
}
<|endoftext|>