<commit_before>#include "coverage.h"
#include "location.h"
#include "geos/geom/Coordinate.h"
#include "coordinate.h"
#include "box.h"
#include "coordinatesystem.h"
#include "georeference.h"
//#include "cornersgeoreference.h"
#include "rootdrawer.h"
#include "spatialdatadrawer.h"
#include "layersrenderer.h"

using namespace Ilwis;
using namespace Geodrawer;

RootDrawer::RootDrawer(const QQuickFramebufferObject *fbo, const IOOptions& options) : ComplexDrawer("RootDrawer",0,0, options), _frameBufferObject(fbo)
{
    valid(true);
    _screenGrf = new GeoReference();
    _screenGrf->create("corners");
}

RootDrawer::~RootDrawer()
{
    cleanUp();
}

void RootDrawer::addSpatialDrawer(DrawerInterface *newdrawer, bool overrule)
{
    overrule = drawerCount(ComplexDrawer::dtMAIN) == 0 || overrule;
    SpatialDataDrawer *datadrawer = dynamic_cast<SpatialDataDrawer *>(newdrawer);
    if ( overrule && datadrawer && datadrawer->coverage().isValid()) {
        ICoordinateSystem cs = datadrawer->coverage()->coordinateSystem();
        Envelope envelope =  envelope2RootEnvelope(cs, datadrawer->envelope());
        Envelope viewEnv = _zoomRect;
        bool setViewEnv =  envelope != viewEnv;
        viewEnv += envelope;
        _coverageRect = datadrawer->envelope();
        if ( setViewEnv)
            applyEnvelopeView(viewEnv, true);

    }
    return ComplexDrawer::addDrawer(newdrawer);
}

void RootDrawer::addEnvelope(const ICoordinateSystem &csSource, const Envelope &env, bool overrule)
{
    if ( overrule || !_coverageRect.isValid() || _coverageRect.isNull()) {
        Envelope newEnvelope = envelope2RootEnvelope(csSource, env);
        _coverageRect += newEnvelope;
    }
    applyEnvelopeView(_coverageRect, overrule);
}

Envelope RootDrawer::viewEnvelope() const
{
    return _viewEnvelope;
}

Envelope RootDrawer::zoomEnvelope() const
{
    return _zoomRect;
}

void RootDrawer::applyEnvelopeView(const Envelope &viewRect, bool overrule)
{
    if ( !_coverageRect.isValid() || _coverageRect.isNull()){
        ERROR2(ERR_NO_INITIALIZED_2,TR("Coverage area"), TR("Visualization"));
        return;
    }
    if ( !_pixelAreaSize.isValid()) {
        ERROR2(ERR_NO_INITIALIZED_2,TR("Pixel area"), TR("Visualization"));
        return;
    }
    if ( overrule)
        _viewEnvelope = Envelope();

    double w = viewRect.xlength() - 1;
    double h = viewRect.ylength() - 1;
    _aspectRatioCoverage = w / h;
    double deltax = 0, deltay = 0;
    Envelope env;
    if ( _aspectRatioCoverage <= 1.0) { // coverage is higher than it is wide)
        double pixwidth = (double)_pixelAreaSize.ysize() * _aspectRatioCoverage;
        if ( pixwidth > _pixelAreaSize.xsize()) {
            deltay = (_coverageRect.ylength() - 1) * ( pixwidth / _pixelAreaSize.xsize() - 1.0);
            pixwidth = _pixelAreaSize.xsize();
        }
        double fractioOffWidth = 1.0 - (_pixelAreaSize.xsize() - pixwidth) / (double)_pixelAreaSize.xsize();
        double crdWidth = w / fractioOffWidth;
        deltax = (crdWidth - w) / 2.0;

        _zoomRect = Envelope(Coordinate(viewRect.min_corner().x - deltax,viewRect.min_corner().y  - deltay/2.0,0),
                             Coordinate(viewRect.max_corner().x + deltax,viewRect.max_corner().y  + deltay/2.0,0));

    } else {
        double pixheight = _pixelAreaSize.xsize() / _aspectRatioCoverage;
        if ( pixheight > _pixelAreaSize.ysize()){
            deltax = (_coverageRect.xlength() - 1) / _aspectRatioCoverage;
            pixheight = _pixelAreaSize.ysize();
        }
        double fractionOfHeight = 1.0 - std::abs(_pixelAreaSize.ysize() - pixheight)/(double)_pixelAreaSize.ysize();
        double crdHeight = h / fractionOfHeight;
        deltay = (crdHeight - h)/ 2.0;
        _zoomRect = Envelope(Coordinate(viewRect.min_corner().x - deltax /2.0,viewRect.min_corner().y  - deltay,0),
                             Coordinate(viewRect.max_corner().x + deltax /2.0,viewRect.max_corner().y  + deltay,0));
    }

    viewPoint(_zoomRect.center(), true);

    setMVP();

}

void RootDrawer::applyEnvelopeZoom(const Envelope &zoomRect)
{
    Envelope envelope = zoomRect;
    if ( _zoomRect.isValid()) {
    // zooming never changes the shape of the mapwindow so any incomming zoom rectangle must conform to the shape of the existing mapwindow

        double factCur = (_zoomRect.xlength() - 1.0) / (_zoomRect.ylength() - 1.0);
        double factIn = (zoomRect.xlength() - 1.0) / (zoomRect.ylength() - 1.0);
        double delta = std::abs(factCur - factIn);
        if (  delta > 0.01 ) {
            if ( factCur < 1.0) {
                double newHeight = (zoomRect.xlength() - 1) / ( factCur * 2.0);
                Coordinate center = zoomRect.center();
                envelope = Envelope(Coordinate(zoomRect.min_corner().x, center.y - newHeight), Coordinate(zoomRect.max_corner().x, center.y - newHeight));
            } else {
                double newWidth = (zoomRect.ylength() - 1) * factCur / 2.0;
                Coordinate center = zoomRect.center();
                envelope = Envelope(Coordinate(center.x - newWidth, zoomRect.min_corner().y), Coordinate(center.x + newWidth, zoomRect.max_corner().y));
            }
        }
    }
    _zoomRect = envelope;
    viewPoint(_zoomRect.center(), true);
    setMVP();

}

void RootDrawer::setMVP()
{
    _projection.setToIdentity();
    QRectF rct(_zoomRect.min_corner().x, _zoomRect.min_corner().y,_zoomRect.xlength() -1,_zoomRect.ylength() - 1);
    _projection.ortho(rct);
    _mvp = _model * _view * _projection;

    if ( _coverageRect.xlength() > 0 && _coverageRect.ylength() > 0) {
        double xscale =  (_zoomRect.xlength() - 1) / (_coverageRect.xlength() - 1);
        double yscale = (_zoomRect.ylength() - 1) /(_coverageRect.ylength() - 1);

        _zoomScale =  std::min(xscale, yscale);
    }
    if ( _viewEnvelope.isNull() && _zoomRect.isValid() && !_zoomRect.isNull())
        _viewEnvelope = _zoomRect;

    _screenGrf->envelope(_zoomRect);
    _screenGrf->size(_pixelAreaSize);
    _screenGrf->compute();

    unprepare(DrawerInterface::ptMVP); // we reset the mvp so for all drawers a new value has to be set to the graphics card
}

void RootDrawer::pixelAreaSize(const Size<>& size)
{
    if ( size == _pixelAreaSize || size.ysize() == 0 || size.xsize() == 0)
        return;

    _aspectRatioView = (double)size.xsize() / (double)size.ysize();
    if ( _aspectRatioCoverage != 0 && !_zoomRect.isNull()){
        double fx = (double)size.xsize() / _pixelAreaSize.xsize();
        double fy = (double)size.ysize() / _pixelAreaSize.ysize();
        double w = _zoomRect.xlength() - 1;
        double h = _zoomRect.ylength() - 1;
        Coordinate center = _zoomRect.center();
        if (  size.xsize() != _pixelAreaSize.xsize() && size.ysize() != _pixelAreaSize.ysize()){
            double dx = w * fx;
            double dy = h * fy;
            _zoomRect = Envelope(Coordinate(center.x - dx / 2.0, center.y - dy / 2.0), Coordinate(center.x + dx / 2.0, center.y + dy / 2.0));

        }else {
            if ( size.xsize() != _pixelAreaSize.xsize())    {
                double dx = w * fx;
                _zoomRect = Envelope(Coordinate(center.x - dx / 2.0, center.y - h / 2.0), Coordinate(center.x + dx / 2.0, center.y + h / 2.0));
            }
            if ( size.ysize() != _pixelAreaSize.ysize())    {
                double dy = h * fy;
                _zoomRect = Envelope(Coordinate(center.x - w / 2.0, center.y - dy / 2.0), Coordinate(center.x + w / 2.0, center.y + dy / 2.0));
            }
        }
    }
    setMVP();
//    auto env = normalizedEnveope(_zoomRect);
//   // qDebug() << "zoom" << env.toString() << env.xlength() * _pixelAreaSize.xsize() << env.ylength() * _pixelAreaSize.ysize();
//    env = normalizedEnveope(_coverageRect);
//    //qDebug() << "cov" << env.toString() << ((env.xlength() - 1) / 2.0) * _pixelAreaSize.xsize() << env.ylength() * _pixelAreaSize.ysize();
//    qDebug() << "cov" << ((env.xlength() - 1) / 2.0) * _pixelAreaSize.xsize() ;

    _pixelAreaSize = size;

}

Size<> RootDrawer::pixelAreaSize() const
{
    return _pixelAreaSize;
}

Size<> RootDrawer::coverageAreaSize() const
{
    if ( !_screenGrf.isValid())
        return Size<>();
    auto bb = _screenGrf->coord2Pixel(_coverageRect);
    return bb.size();
}

const QMatrix4x4 &RootDrawer::mvpMatrix() const
{
    return _mvp;
}

const ICoordinateSystem &RootDrawer::coordinateSystem() const
{
    return _coordinateSystem;
}

void RootDrawer::coordinateSystem(const ICoordinateSystem &csy)
{
    _coordinateSystem = csy;
}

const IGeoReference &RootDrawer::screenGrf() const
{
    return _screenGrf;
}

void RootDrawer::viewPoint(const Coordinate& viewCenter, bool setEyePoint){
    _viewPoint = viewCenter;
    if ( setEyePoint){
        _eyePoint.x = _viewPoint.x;
        _eyePoint.y = _viewPoint.y - _zoomRect.ylength() * 1.5;
        _eyePoint.z = _zoomRect.xlength() ;
    }
}

void RootDrawer::cleanUp()
{
    ComplexDrawer::cleanUp();
}

bool RootDrawer::prepare(DrawerInterface::PreparationType prepType, const IOOptions &options)
{
    return ComplexDrawer::prepare(prepType, options)    ;
}

double RootDrawer::aspectRatioView() const
{
    return _aspectRatioView;
}

double RootDrawer::zoomScale() const
{
    return _zoomScale;
}

bool RootDrawer::is3D() const
{
    return _is3D;
}

void RootDrawer::set3D(bool yesno)
{
    _is3D = yesno;
}

const QQuickFramebufferObject *RootDrawer::fbo() const
{
    return _frameBufferObject;
}

Envelope RootDrawer::envelope2RootEnvelope(const ICoordinateSystem &csSource, const Envelope &env)
{
    Envelope envelope = (!_coordinateSystem.isValid() ||
                         !csSource.isValid() ||
                         _coordinateSystem->isEqual(csSource.ptr()) ||
                         _coordinateSystem->isUnknown() ||
                         csSource->isUnknown()) ?
                env : _coordinateSystem->convertEnvelope(csSource, env);

    return envelope;
}

DrawerInterface::DrawerType RootDrawer::drawerType() const
{
    return DrawerInterface::dtDONTCARE; // rootdrawer is never child of anything so it never is a pre,post, or main drawer. it is the root
}

QVariant RootDrawer::attribute(const QString &attrNme) const
{
    QString attrName = attrNme.toLower();
    QVariant var = ComplexDrawer::attribute(attrName);
    if ( var.isValid())
        return var;

    if ( attrName == "coordinatesystem"){
        QVariant var = qVariantFromValue(coordinateSystem());
        return var;
    }
    if ( attrName == "coverageenvelope"){
        QVariant var = qVariantFromValue(_coverageRect);
        return var;
    }

    if ( attrName == "zoomenvelope"){
        QVariant var = qVariantFromValue(_zoomRect);
        return var;
    }
    return QVariant();
}

void RootDrawer::redraw()
{
    emit updateRenderer();
}

Ilwis::Coordinate RootDrawer::normalizedCoord(const Coordinate& crd) const{
    QVector3D v1( crd.x,crd.y, crd.is3D()? crd.z : 0);
    QVector3D a1 = _mvp * v1;
    return Ilwis::Coordinate(a1);
}

Envelope RootDrawer::normalizedEnveope(const Envelope& env) const
{
    Ilwis::Coordinate v1normalized =normalizedCoord(env.min_corner());
    Ilwis::Coordinate v2normalized = normalizedCoord(env.max_corner());
    return Envelope(v1normalized, v2normalized);
}

Ilwis::Coordinate RootDrawer::pixel2Coord(const Ilwis::Pixel& pix){
    if ( _screenGrf.isValid())
        return _screenGrf->pixel2Coord(pix);
    return Ilwis::Coordinate();
}

<commit_msg>areas of 1 size ( meaning realy 0 size, +1 for the odity with boxes) no operation needs to be done<commit_after>#include "coverage.h"
#include "location.h"
#include "geos/geom/Coordinate.h"
#include "coordinate.h"
#include "box.h"
#include "coordinatesystem.h"
#include "georeference.h"
//#include "cornersgeoreference.h"
#include "rootdrawer.h"
#include "spatialdatadrawer.h"
#include "layersrenderer.h"

using namespace Ilwis;
using namespace Geodrawer;

RootDrawer::RootDrawer(const QQuickFramebufferObject *fbo, const IOOptions& options) : ComplexDrawer("RootDrawer",0,0, options), _frameBufferObject(fbo)
{
    valid(true);
    _screenGrf = new GeoReference();
    _screenGrf->create("corners");
}

RootDrawer::~RootDrawer()
{
    cleanUp();
}

void RootDrawer::addSpatialDrawer(DrawerInterface *newdrawer, bool overrule)
{
    overrule = drawerCount(ComplexDrawer::dtMAIN) == 0 || overrule;
    SpatialDataDrawer *datadrawer = dynamic_cast<SpatialDataDrawer *>(newdrawer);
    if ( overrule && datadrawer && datadrawer->coverage().isValid()) {
        ICoordinateSystem cs = datadrawer->coverage()->coordinateSystem();
        Envelope envelope =  envelope2RootEnvelope(cs, datadrawer->envelope());
        Envelope viewEnv = _zoomRect;
        bool setViewEnv =  envelope != viewEnv;
        viewEnv += envelope;
        _coverageRect = datadrawer->envelope();
        if ( setViewEnv)
            applyEnvelopeView(viewEnv, true);

    }
    return ComplexDrawer::addDrawer(newdrawer);
}

void RootDrawer::addEnvelope(const ICoordinateSystem &csSource, const Envelope &env, bool overrule)
{
    if ( overrule || !_coverageRect.isValid() || _coverageRect.isNull()) {
        Envelope newEnvelope = envelope2RootEnvelope(csSource, env);
        _coverageRect += newEnvelope;
    }
    applyEnvelopeView(_coverageRect, overrule);
}

Envelope RootDrawer::viewEnvelope() const
{
    return _viewEnvelope;
}

Envelope RootDrawer::zoomEnvelope() const
{
    return _zoomRect;
}

void RootDrawer::applyEnvelopeView(const Envelope &viewRect, bool overrule)
{
    if ( !_coverageRect.isValid() || _coverageRect.isNull()){
        ERROR2(ERR_NO_INITIALIZED_2,TR("Coverage area"), TR("Visualization"));
        return;
    }
    if ( !_pixelAreaSize.isValid()) {
        ERROR2(ERR_NO_INITIALIZED_2,TR("Pixel area"), TR("Visualization"));
        return;
    }
    if ( overrule)
        _viewEnvelope = Envelope();

    double w = viewRect.xlength() - 1;
    double h = viewRect.ylength() - 1;
    _aspectRatioCoverage = w / h;
    double deltax = 0, deltay = 0;
    Envelope env;
    if ( _aspectRatioCoverage <= 1.0) { // coverage is higher than it is wide)
        double pixwidth = (double)_pixelAreaSize.ysize() * _aspectRatioCoverage;
        if ( pixwidth > _pixelAreaSize.xsize()) {
            deltay = (_coverageRect.ylength() - 1) * ( pixwidth / _pixelAreaSize.xsize() - 1.0);
            pixwidth = _pixelAreaSize.xsize();
        }
        double fractioOffWidth = 1.0 - (_pixelAreaSize.xsize() - pixwidth) / (double)_pixelAreaSize.xsize();
        double crdWidth = w / fractioOffWidth;
        deltax = (crdWidth - w) / 2.0;

        _zoomRect = Envelope(Coordinate(viewRect.min_corner().x - deltax,viewRect.min_corner().y  - deltay/2.0,0),
                             Coordinate(viewRect.max_corner().x + deltax,viewRect.max_corner().y  + deltay/2.0,0));

    } else {
        double pixheight = _pixelAreaSize.xsize() / _aspectRatioCoverage;
        if ( pixheight > _pixelAreaSize.ysize()){
            deltax = (_coverageRect.xlength() - 1) / _aspectRatioCoverage;
            pixheight = _pixelAreaSize.ysize();
        }
        double fractionOfHeight = 1.0 - std::abs(_pixelAreaSize.ysize() - pixheight)/(double)_pixelAreaSize.ysize();
        double crdHeight = h / fractionOfHeight;
        deltay = (crdHeight - h)/ 2.0;
        _zoomRect = Envelope(Coordinate(viewRect.min_corner().x - deltax /2.0,viewRect.min_corner().y  - deltay,0),
                             Coordinate(viewRect.max_corner().x + deltax /2.0,viewRect.max_corner().y  + deltay,0));
    }

    viewPoint(_zoomRect.center(), true);

    setMVP();

}

void RootDrawer::applyEnvelopeZoom(const Envelope &zoomRect)
{
    if ( zoomRect.area() == 1) // we dont zoom in on pointsize area
        return;

    Envelope envelope = zoomRect;
    if ( _zoomRect.isValid()) {
    // zooming never changes the shape of the mapwindow so any incomming zoom rectangle must conform to the shape of the existing mapwindow

        double factCur = (_zoomRect.xlength() - 1.0) / (_zoomRect.ylength() - 1.0);
        double factIn = (zoomRect.xlength() - 1.0) / (zoomRect.ylength() - 1.0);
        double delta = std::abs(factCur - factIn);
        if (  delta > 0.01 ) {
            if ( factCur < 1.0) {
                double newHeight = (zoomRect.xlength() - 1) / ( factCur * 2.0);
                Coordinate center = zoomRect.center();
                envelope = Envelope(Coordinate(zoomRect.min_corner().x, center.y - newHeight), Coordinate(zoomRect.max_corner().x, center.y - newHeight));
            } else {
                double newWidth = (zoomRect.ylength() - 1) * factCur / 2.0;
                Coordinate center = zoomRect.center();
                envelope = Envelope(Coordinate(center.x - newWidth, zoomRect.min_corner().y), Coordinate(center.x + newWidth, zoomRect.max_corner().y));
            }
        }
    }
    _zoomRect = envelope;
    viewPoint(_zoomRect.center(), true);
    setMVP();

}

void RootDrawer::setMVP()
{
    _projection.setToIdentity();
    QRectF rct(_zoomRect.min_corner().x, _zoomRect.min_corner().y,_zoomRect.xlength() -1,_zoomRect.ylength() - 1);
    _projection.ortho(rct);
    _mvp = _model * _view * _projection;

    if ( _coverageRect.xlength() > 0 && _coverageRect.ylength() > 0) {
        double xscale =  (_zoomRect.xlength() - 1) / (_coverageRect.xlength() - 1);
        double yscale = (_zoomRect.ylength() - 1) /(_coverageRect.ylength() - 1);

        _zoomScale =  std::min(xscale, yscale);
    }
    if ( _viewEnvelope.isNull() && _zoomRect.isValid() && !_zoomRect.isNull())
        _viewEnvelope = _zoomRect;

    _screenGrf->envelope(_zoomRect);
    _screenGrf->size(_pixelAreaSize);
    _screenGrf->compute();

    unprepare(DrawerInterface::ptMVP); // we reset the mvp so for all drawers a new value has to be set to the graphics card
}

void RootDrawer::pixelAreaSize(const Size<>& size)
{
    if ( size == _pixelAreaSize || size.ysize() == 0 || size.xsize() == 0)
        return;

    _aspectRatioView = (double)size.xsize() / (double)size.ysize();
    if ( _aspectRatioCoverage != 0 && !_zoomRect.isNull()){
        double fx = (double)size.xsize() / _pixelAreaSize.xsize();
        double fy = (double)size.ysize() / _pixelAreaSize.ysize();
        double w = _zoomRect.xlength() - 1;
        double h = _zoomRect.ylength() - 1;
        Coordinate center = _zoomRect.center();
        if (  size.xsize() != _pixelAreaSize.xsize() && size.ysize() != _pixelAreaSize.ysize()){
            double dx = w * fx;
            double dy = h * fy;
            _zoomRect = Envelope(Coordinate(center.x - dx / 2.0, center.y - dy / 2.0), Coordinate(center.x + dx / 2.0, center.y + dy / 2.0));

        }else {
            if ( size.xsize() != _pixelAreaSize.xsize())    {
                double dx = w * fx;
                _zoomRect = Envelope(Coordinate(center.x - dx / 2.0, center.y - h / 2.0), Coordinate(center.x + dx / 2.0, center.y + h / 2.0));
            }
            if ( size.ysize() != _pixelAreaSize.ysize())    {
                double dy = h * fy;
                _zoomRect = Envelope(Coordinate(center.x - w / 2.0, center.y - dy / 2.0), Coordinate(center.x + w / 2.0, center.y + dy / 2.0));
            }
        }
    }
    setMVP();
//    auto env = normalizedEnveope(_zoomRect);
//   // qDebug() << "zoom" << env.toString() << env.xlength() * _pixelAreaSize.xsize() << env.ylength() * _pixelAreaSize.ysize();
//    env = normalizedEnveope(_coverageRect);
//    //qDebug() << "cov" << env.toString() << ((env.xlength() - 1) / 2.0) * _pixelAreaSize.xsize() << env.ylength() * _pixelAreaSize.ysize();
//    qDebug() << "cov" << ((env.xlength() - 1) / 2.0) * _pixelAreaSize.xsize() ;

    _pixelAreaSize = size;

}

Size<> RootDrawer::pixelAreaSize() const
{
    return _pixelAreaSize;
}

Size<> RootDrawer::coverageAreaSize() const
{
    if ( !_screenGrf.isValid())
        return Size<>();
    auto bb = _screenGrf->coord2Pixel(_coverageRect);
    return bb.size();
}

const QMatrix4x4 &RootDrawer::mvpMatrix() const
{
    return _mvp;
}

const ICoordinateSystem &RootDrawer::coordinateSystem() const
{
    return _coordinateSystem;
}

void RootDrawer::coordinateSystem(const ICoordinateSystem &csy)
{
    _coordinateSystem = csy;
}

const IGeoReference &RootDrawer::screenGrf() const
{
    return _screenGrf;
}

void RootDrawer::viewPoint(const Coordinate& viewCenter, bool setEyePoint){
    _viewPoint = viewCenter;
    if ( setEyePoint){
        _eyePoint.x = _viewPoint.x;
        _eyePoint.y = _viewPoint.y - _zoomRect.ylength() * 1.5;
        _eyePoint.z = _zoomRect.xlength() ;
    }
}

void RootDrawer::cleanUp()
{
    ComplexDrawer::cleanUp();
}

bool RootDrawer::prepare(DrawerInterface::PreparationType prepType, const IOOptions &options)
{
    return ComplexDrawer::prepare(prepType, options)    ;
}

double RootDrawer::aspectRatioView() const
{
    return _aspectRatioView;
}

double RootDrawer::zoomScale() const
{
    return _zoomScale;
}

bool RootDrawer::is3D() const
{
    return _is3D;
}

void RootDrawer::set3D(bool yesno)
{
    _is3D = yesno;
}

const QQuickFramebufferObject *RootDrawer::fbo() const
{
    return _frameBufferObject;
}

Envelope RootDrawer::envelope2RootEnvelope(const ICoordinateSystem &csSource, const Envelope &env)
{
    Envelope envelope = (!_coordinateSystem.isValid() ||
                         !csSource.isValid() ||
                         _coordinateSystem->isEqual(csSource.ptr()) ||
                         _coordinateSystem->isUnknown() ||
                         csSource->isUnknown()) ?
                env : _coordinateSystem->convertEnvelope(csSource, env);

    return envelope;
}

DrawerInterface::DrawerType RootDrawer::drawerType() const
{
    return DrawerInterface::dtDONTCARE; // rootdrawer is never child of anything so it never is a pre,post, or main drawer. it is the root
}

QVariant RootDrawer::attribute(const QString &attrNme) const
{
    QString attrName = attrNme.toLower();
    QVariant var = ComplexDrawer::attribute(attrName);
    if ( var.isValid())
        return var;

    if ( attrName == "coordinatesystem"){
        QVariant var = qVariantFromValue(coordinateSystem());
        return var;
    }
    if ( attrName == "coverageenvelope"){
        QVariant var = qVariantFromValue(_coverageRect);
        return var;
    }

    if ( attrName == "zoomenvelope"){
        QVariant var = qVariantFromValue(_zoomRect);
        return var;
    }
    return QVariant();
}

void RootDrawer::redraw()
{
    emit updateRenderer();
}

Ilwis::Coordinate RootDrawer::normalizedCoord(const Coordinate& crd) const{
    QVector3D v1( crd.x,crd.y, crd.is3D()? crd.z : 0);
    QVector3D a1 = _mvp * v1;
    return Ilwis::Coordinate(a1);
}

Envelope RootDrawer::normalizedEnveope(const Envelope& env) const
{
    Ilwis::Coordinate v1normalized =normalizedCoord(env.min_corner());
    Ilwis::Coordinate v2normalized = normalizedCoord(env.max_corner());
    return Envelope(v1normalized, v2normalized);
}

Ilwis::Coordinate RootDrawer::pixel2Coord(const Ilwis::Pixel& pix){
    if ( _screenGrf.isValid())
        return _screenGrf->pixel2Coord(pix);
    return Ilwis::Coordinate();
}

<|endoftext|>


<commit_before>
#include <gtest/gtest.h>
#include <alcommon-ng/common/common.hpp>
#include <alcommon-ng/tools/dataperftimer.hpp>
#include <boost/timer.hpp>
#include <string>

using namespace AL::Common;
using namespace AL::Messaging;

std::string gMasterAddress = "127.0.0.1:5555";
std::string gServerName = "server";
std::string gServerAddress = "127.0.0.1:5556";

TEST(ClientNode, createWithStupidMasterPort)
{
  ClientNode client("client", "blabla");
  client.call("ognagnuk");
}

TEST(ServerNode, createWithStupidMasterPort)
{
  ServerNode server("server", "blabla", "oink");
}

TEST(MasterNode, createWithStupidMasterPort)
{
  MasterNode master("oink2");
}

TEST(ServerNode, createWithStupidServerPort)
{
  MasterNode master("127.0.0.1:6666");
  ServerNode server("server", "blabla", "127.0.0.1:6666");
}

MasterNode gMaster(gMasterAddress);
ServerNode gServer(gServerName, gServerAddress, gMasterAddress);
ClientNode gClient("client", gMasterAddress);

std::string echo(const std::string& in) {
  return in;
}

TEST(Nodes, NormalUsage)
{
  std::cout << "TEST: Initialized " << std::endl;
  std::cout << "TEST: Calling master.listServices " << std::endl;
  ReturnValue result1 = gClient.call("master.listServices");

  std::cout << "TEST: Binding wibble.echo " << std::endl;
  gServer.addService("wibble.echo", &echo);
  std::cout << "TEST: Calling wibble.echo " << std::endl;

  std::cout << "TEST: Calling master.gobledigook " << std::endl;
  ReturnValue result4 = gClient.call("master.gobledigook");

  //for(int i=0; i<100; i++) {
  //  ReturnValue result5 = gClient.call("master.listServices");
  //}
}

TEST(Nodes, Performance)
{
  unsigned int numMessages = 1000;
  unsigned int numPowers = 12;
  AL::Test::DataPerfTimer dt("NodeCalls");
  char character = 'A';

  // loop message sizes 2^i bytes
  for (unsigned int i = 1; i < numPowers; i++) {
    unsigned int numBytes = (unsigned int)pow(2.0f, (int)i);
    std::string request = std::string(numBytes, character);
    ArgumentList args;
    ReturnValue result;
    args.push_back(request);

    dt.start(numMessages, numBytes);
    for (unsigned int loop = 0; loop < numMessages; loop++) {
      // Serialize
      gClient.call("wibble.echo", args, result);
    }
    dt.stop();
  }

}
<commit_msg>More node tests<commit_after>
#include <gtest/gtest.h>
#include <alcommon-ng/common/common.hpp>
#include <alcommon-ng/tools/dataperftimer.hpp>
#include <boost/timer.hpp>
#include <string>

using namespace AL::Common;
using namespace AL::Messaging;

std::string gMasterAddress = "127.0.0.1:5555";
std::string gServerName = "server";
std::string gServerAddress = "127.0.0.1:5556";

TEST(ClientNode, createWithStupidMasterPort)
{
  ClientNode client("client", "blabla");
  client.call("ognagnuk");
}

TEST(ServerNode, createWithStupidMasterPort)
{
  ServerNode server("server", "blabla", "oink");
}

TEST(MasterNode, createWithStupidMasterPort)
{
  MasterNode master("oink2");
}

TEST(ServerNode, createWithStupidServerPort)
{
  MasterNode master("127.0.0.1:6666");
  ServerNode server("server", "blabla", "127.0.0.1:6666");
}

MasterNode gMaster(gMasterAddress);
ServerNode gServer(gServerName, gServerAddress, gMasterAddress);
ClientNode gClient("client", gMasterAddress);

void ping() {
}

std::string echo(const std::string& in) {
  return in;
}

TEST(Nodes, NormalUsage)
{
  std::cout << "TEST: Initialized " << std::endl;
  std::cout << "TEST: Calling master.listServices " << std::endl;
  ReturnValue result1 = gClient.call("master.listServices");

  std::cout << "TEST: Binding wibble.echo " << std::endl;
  gServer.addService("wibble.echo", &echo);
  //std::cout << "TEST: Calling wibble.echo " << std::endl;

  std::cout << "TEST: Binding wibble.ping " << std::endl;
  gServer.addService("wibble.ping", &ping);
  gClient.call("wibble.ping");
  //std::cout << "TEST: Calling wibble.ping " << std::endl;

  std::cout << "TEST: Calling master.gobledigook " << std::endl;
  ReturnValue result4 = gClient.call("master.gobledigook");

  //for(int i=0; i<100; i++) {
  //  ReturnValue result5 = gClient.call("master.listServices");
  //}
}

TEST(Nodes, PerformancePing)
{
  unsigned int numMessages = 10000;

  AL::Test::DataPerfTimer dt("NodeCalls");

  dt.start(numMessages);
  for (unsigned int loop = 0; loop < numMessages; loop++) {
    // Serialize
    gClient.call("wibble.ping");
  }
  dt.stop();
}

TEST(Nodes, PerformanceEcho)
{
  unsigned int numMessages = 10000;
  unsigned int numPowers = 12;
  AL::Test::DataPerfTimer dt("NodeCalls");
  char character = 'A';

  // loop message sizes 2^i bytes
  for (unsigned int i = 1; i < numPowers; i++) {
    unsigned int numBytes = (unsigned int)pow(2.0f, (int)i);
    std::string request = std::string(numBytes, character);
    ArgumentList args;
    ReturnValue result;
    args.push_back(request);

    dt.start(numMessages, numBytes);
    for (unsigned int loop = 0; loop < numMessages; loop++) {
      // Serialize
      gClient.call("wibble.echo", args, result);
    }
    dt.stop();
  }

}
<|endoftext|>


<commit_before>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// This file contains tests for |RtpTransceiver|.

#include "pc/rtptransceiver.h"

#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_channelinterface.h"

using ::testing::Return;
using ::testing::ReturnRef;

namespace webrtc {

// Checks that a channel cannot be set on a stopped |RtpTransceiver|.
TEST(RtpTransceiverTest, CannotSetChannelOnStoppedTransceiver) {
  RtpTransceiver transceiver(cricket::MediaType::MEDIA_TYPE_AUDIO);
  cricket::MockChannelInterface channel1;
  sigslot::signal1<cricket::ChannelInterface*> signal;
  EXPECT_CALL(channel1, media_type())
      .WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
  EXPECT_CALL(channel1, SignalFirstPacketReceived())
      .WillRepeatedly(ReturnRef(signal));

  transceiver.SetChannel(&channel1);
  EXPECT_EQ(&channel1, transceiver.channel());

  // Stop the transceiver.
  transceiver.Stop();
  EXPECT_EQ(&channel1, transceiver.channel());

  cricket::MockChannelInterface channel2;
  EXPECT_CALL(channel2, media_type())
      .WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));

  // Channel can no longer be set, so this call should be a no-op.
  transceiver.SetChannel(&channel2);
  EXPECT_EQ(&channel1, transceiver.channel());
}

// Checks that a channel can be unset on a stopped |RtpTransceiver|
TEST(RtpTransceiverTest, CanUnsetChannelOnStoppedTransceiver) {
  RtpTransceiver transceiver(cricket::MediaType::MEDIA_TYPE_VIDEO);
  cricket::MockChannelInterface channel;
  sigslot::signal1<cricket::ChannelInterface*> signal;
  EXPECT_CALL(channel, media_type())
      .WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_VIDEO));
  EXPECT_CALL(channel, SignalFirstPacketReceived())
      .WillRepeatedly(ReturnRef(signal));

  transceiver.SetChannel(&channel);
  EXPECT_EQ(&channel, transceiver.channel());

  // Stop the transceiver.
  transceiver.Stop();
  EXPECT_EQ(&channel, transceiver.channel());

  // Set the channel to |nullptr|.
  transceiver.SetChannel(nullptr);
  EXPECT_EQ(nullptr, transceiver.channel());
}

}  // namespace webrtc
<commit_msg>Use project-level include path in rtptransceiver_unittest.cc<commit_after>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// This file contains tests for |RtpTransceiver|.

#include "pc/rtptransceiver.h"

#include "pc/test/mock_channelinterface.h"
#include "test/gmock.h"
#include "test/gtest.h"

using ::testing::Return;
using ::testing::ReturnRef;

namespace webrtc {

// Checks that a channel cannot be set on a stopped |RtpTransceiver|.
TEST(RtpTransceiverTest, CannotSetChannelOnStoppedTransceiver) {
  RtpTransceiver transceiver(cricket::MediaType::MEDIA_TYPE_AUDIO);
  cricket::MockChannelInterface channel1;
  sigslot::signal1<cricket::ChannelInterface*> signal;
  EXPECT_CALL(channel1, media_type())
      .WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
  EXPECT_CALL(channel1, SignalFirstPacketReceived())
      .WillRepeatedly(ReturnRef(signal));

  transceiver.SetChannel(&channel1);
  EXPECT_EQ(&channel1, transceiver.channel());

  // Stop the transceiver.
  transceiver.Stop();
  EXPECT_EQ(&channel1, transceiver.channel());

  cricket::MockChannelInterface channel2;
  EXPECT_CALL(channel2, media_type())
      .WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));

  // Channel can no longer be set, so this call should be a no-op.
  transceiver.SetChannel(&channel2);
  EXPECT_EQ(&channel1, transceiver.channel());
}

// Checks that a channel can be unset on a stopped |RtpTransceiver|
TEST(RtpTransceiverTest, CanUnsetChannelOnStoppedTransceiver) {
  RtpTransceiver transceiver(cricket::MediaType::MEDIA_TYPE_VIDEO);
  cricket::MockChannelInterface channel;
  sigslot::signal1<cricket::ChannelInterface*> signal;
  EXPECT_CALL(channel, media_type())
      .WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_VIDEO));
  EXPECT_CALL(channel, SignalFirstPacketReceived())
      .WillRepeatedly(ReturnRef(signal));

  transceiver.SetChannel(&channel);
  EXPECT_EQ(&channel, transceiver.channel());

  // Stop the transceiver.
  transceiver.Stop();
  EXPECT_EQ(&channel, transceiver.channel());

  // Set the channel to |nullptr|.
  transceiver.SetChannel(nullptr);
  EXPECT_EQ(nullptr, transceiver.channel());
}

}  // namespace webrtc
<|endoftext|>


<commit_before>#include "math/MatrixTransform.hpp"
#include "math/Ray.hpp"
#include "math/Sphere.hpp"
#include "math/TransformPair.hpp"
#include "math/mat.hpp"
#include "math/misc.hpp"
#include "math/vec.hpp"
#include "Optional.hpp"
#include "noncopyable.hpp"

#include "materials/Material.hpp"
#include "materials/TextureCheckerboard.hpp"
#include "materials/TextureSolid.hpp"
#include "materials/texture_mappings.hpp"

#include "shapes/SceneShape.hpp"
#include "shapes/ShapeSphere.hpp"
#include "shapes/ShapePlane.hpp"

#include "output.hpp"

#include <algorithm>
#include <limits>
#include <memory>
#include <vector>
#include <random>

using namespace yks;

struct Rng {
	std::mt19937 engine;
	std::uniform_real_distribution<float> canonical_distribution; // std::generate_canonical is broken in VS2013

	Rng() {
		static const uint32_t seed_seq[] = {
			0x4587ba0e, 0xad01370f, 0xdd817882, 0xdc98c4aa,
			0x4cbf0235, 0x7dba82eb, 0xea593627, 0x597e5052
		};
		std::seed_seq seq(std::begin(seed_seq), std::end(seed_seq));
		engine.seed(seq);
	}

	float canonical() {
		return canonical_distribution(engine);
	}
};

struct SceneObject {
	Material material;
	std::unique_ptr<SceneShape> shape;

	SceneObject(Material material, std::unique_ptr<SceneShape>&& shape)
		: material(material), shape(std::move(shape))
	{}

	SceneObject(SceneObject&& o)
		: material(std::move(o.material)), shape(std::move(o.shape))
	{}

private:
	NONCOPYABLE(SceneObject);
};

struct SceneLight {
	vec3 origin;
	vec3 intensity;
	float radius;

	// Emittance = Power / (4*pi*radius^2)
	// Intensity = Emittance / 2*pi
	SceneLight(const vec3& origin, const vec3& total_power, float radius)
		: origin(origin), intensity(total_power * (1.0f / (2*radius*radius))), radius(radius)
	{}

	vec3 samplePoint(Rng& rng) const {
		const float a = rng.canonical();
		const float b = rng.canonical();
		return uniform_point_on_sphere(a, b) * radius + origin;
	}

	vec3 calcIntensity(const vec3& point, const vec3& direction) const {
		return dot(point - origin, direction) >= 0.0f ? intensity : vec3_0;
	}
};

float focal_distance_from_fov(const float fov_degrees) {
	const float half_fov = fov_degrees / 360.0f * pi;
	return std::tan(0.5f*pi - half_fov);
}

struct Camera {
	vec3 origin;
	mat3 orientation;
	float focal_length; // distance from image plane

	Camera(vec3 origin, mat3 orientation, float vertical_fov)
		: origin(origin), orientation(orientation), focal_length(focal_distance_from_fov(vertical_fov))
	{}

	Ray createRay(const vec2 film_pos) const {
		const vec3 cameraspace_ray = mvec3(film_pos[0], film_pos[1], focal_length);
		return Ray{origin, orientation * cameraspace_ray};
	}
};

struct Scene {
	Camera camera;
	std::vector<SceneObject> objects;
	std::vector<SceneLight> lights;

	Scene(Camera camera)
		: camera(camera)
	{}

	Scene(Scene&& o)
		: camera(std::move(o.camera)), objects(std::move(o.objects)), lights(std::move(o.lights))
	{}

private:
	NONCOPYABLE(Scene);
};

Scene setup_scene() {
	const auto black = std::make_shared<TextureSolid>(vec3_0);
	const auto white = std::make_shared<TextureSolid>(vec3_1);
	const auto red = std::make_shared<TextureSolid>(vec3_x);

	Scene s(Camera(vec3_y * 0.2, orient(vec3_y, -vec3_z), 75.0f));
	s.objects.push_back(SceneObject(
		Material(black, std::make_shared<TextureSolid>(1.0f, 0.4f, 0.4f)),
		std::make_unique<ShapeSphere>(TransformPair().translate(mvec3(0.0f, 0.0f, -5.0f)))
		));
	s.objects.push_back(SceneObject(
		Material(white, black),
		std::make_unique<ShapeSphere>(TransformPair().scale(0.25f).translate(mvec3(-0.5f, 1.5f, -3.0f)))
		));

	const mat<2, 4> plane_tex_mapping = {{
		1, 0, 0, 0,
		0, 0, 1, 0
	}};
	const auto checkerboard = std::make_shared<TextureCheckerboard>(white, red);

	s.objects.push_back(SceneObject(
		Material(std::make_shared<TexMapFromPosition>(checkerboard, plane_tex_mapping), white),
		std::make_unique<ShapePlane>(TransformPair().translate(vec3_y * -1.0f))
		));

	s.lights.push_back(SceneLight(mvec3(-2.0f, 4.0f, -4.0f), vec3_1 * 40, 1));

	return std::move(s);
}

static vec2 filmspace_from_screenspace(const vec2 screen_pos, const vec2 screen_size) {
	return (screen_pos - (screen_size * 0.5f)) * 2.0f * (1.0f / screen_size[1]);
}

Optional<Intersection> find_nearest_intersection(const Scene& scene, const Ray ray) {
	Optional<Intersection> nearest_intersection;

	for (const SceneObject& object : scene.objects) {
		const Optional<Intersection> intersection = object.shape->intersect(ray);
		if (intersection && (!nearest_intersection || intersection->t < nearest_intersection->t)) {
			nearest_intersection = intersection;
			nearest_intersection->object = &object;
			nearest_intersection->shape = object.shape.get();
		}
	}

	return nearest_intersection;
}

bool find_any_intersection(const Scene& scene, const Ray& ray, float max_t) {
	for (const SceneObject& object : scene.objects) {
		if (object.shape->hasIntersection(ray, max_t)) {
			return true;
		}
	}

	return false;
}

vec3 reflect(const vec3& l, const vec3& n) {
	return l + 2*dot(n, -l) * n;
}

static const float RAY_EPSILON = 1e-6f;

vec3 calc_light_incidence(const Scene& scene, Rng& rng, const Ray& ray, int remaining_depth) {
	vec3 color = vec3_0;

	const Optional<Intersection> surface_hit = find_nearest_intersection(scene, ray);
	if (surface_hit) {
		for (const SceneLight& light : scene.lights) {
			const vec3 light_sample = light.samplePoint(rng);
			const vec3 light_vec = light_sample - surface_hit->position;

			if (!find_any_intersection(scene, Ray{surface_hit->position + surface_hit->normal * RAY_EPSILON, light_vec}, 1.0f)) {
				const vec3 albedo = surface_hit->object->material.diffuse->getValue(*surface_hit);
				color += albedo * std::max(0.0f, dot(normalized(light_vec), surface_hit->normal)) * (light.calcIntensity(light_sample, -light_vec) * (1.0f / dot(light_vec, light_vec)));
			}
		}

		const vec3 specular_reflectance = surface_hit->object->material.specular->getValue(*surface_hit);
		if (remaining_depth > 0 && specular_reflectance != vec3_0) {
			color += specular_reflectance * calc_light_incidence(scene, rng, Ray{surface_hit->position + surface_hit->normal * RAY_EPSILON, reflect(normalized(ray.direction), surface_hit->normal)}, remaining_depth-1);
		} else {
			color += specular_reflectance * 0.5f;
		}
	} else {
		color = vec3_0;
	}

	return color;
}

int main(int, char* []) {
	static const int IMAGE_WIDTH = 1280;
	static const int IMAGE_HEIGHT = 720;
	std::vector<vec3> image_data(IMAGE_WIDTH * IMAGE_HEIGHT);

	const Scene scene = setup_scene();
	Rng rng;

	for (int y = 0; y < IMAGE_HEIGHT; ++y) {
		for (int x = 0; x < IMAGE_WIDTH; x++) {
			const vec2 film_coord = filmspace_from_screenspace(mvec2(float(x), float(y)), mvec2(float(IMAGE_WIDTH), float(IMAGE_HEIGHT))) * mvec2(1.0f, -1.0f);
			const Ray camera_ray = scene.camera.createRay(film_coord);

			image_data[y*IMAGE_WIDTH + x] = calc_light_incidence(scene, rng, camera_ray, 5);
		}
	}

	save_srgb_image(image_data, IMAGE_WIDTH, IMAGE_HEIGHT);
}
<commit_msg>Properly implement Monte Carlo sampling acoording to theory.<commit_after>#include "math/MatrixTransform.hpp"
#include "math/Ray.hpp"
#include "math/Sphere.hpp"
#include "math/TransformPair.hpp"
#include "math/mat.hpp"
#include "math/misc.hpp"
#include "math/vec.hpp"
#include "Optional.hpp"
#include "noncopyable.hpp"

#include "materials/Material.hpp"
#include "materials/TextureCheckerboard.hpp"
#include "materials/TextureSolid.hpp"
#include "materials/texture_mappings.hpp"

#include "shapes/SceneShape.hpp"
#include "shapes/ShapeSphere.hpp"
#include "shapes/ShapePlane.hpp"

#include "output.hpp"

#include <algorithm>
#include <limits>
#include <memory>
#include <vector>
#include <random>
#include <iostream>

using namespace yks;

struct Rng {
	std::mt19937 engine;
	std::uniform_real_distribution<float> canonical_distribution; // std::generate_canonical is broken in VS2013

	Rng() {
		static const uint32_t seed_seq[] = {
			0x4587ba0e, 0xad01370f, 0xdd817882, 0xdc98c4aa,
			0x4cbf0235, 0x7dba82eb, 0xea593627, 0x597e5052
		};
		std::seed_seq seq(std::begin(seed_seq), std::end(seed_seq));
		engine.seed(seq);
	}

	float canonical() {
		return canonical_distribution(engine);
	}
};

struct SceneObject {
	Material material;
	std::unique_ptr<SceneShape> shape;

	SceneObject(Material material, std::unique_ptr<SceneShape>&& shape)
		: material(material), shape(std::move(shape))
	{}

	SceneObject(SceneObject&& o)
		: material(std::move(o.material)), shape(std::move(o.shape))
	{}

private:
	NONCOPYABLE(SceneObject);
};

struct LightSample {
	vec3 point;
	float pdf;
};

struct SceneLight {
	vec3 origin;
	vec3 intensity;
	float radius;

	// Emittance = Power / Area = Power / (4*pi*radius^2)
	// Intensity = Emittance / (2*pi) = Power / (8*pi^2*radius^2)
	SceneLight(const vec3& origin, const vec3& total_power, float radius)
		: origin(origin), intensity(total_power * (1.0f / (8*pi*pi)) * (1.0f / sqr(radius))), radius(radius)
	{}

	LightSample samplePoint(Rng& rng) const {
		const float a = rng.canonical();
		const float b = rng.canonical();
		return LightSample{
			uniform_point_on_sphere(a, b) * radius + origin,
			1.0f / (4.0f * pi * sqr(radius)),
		};
	}

	vec3 calcIntensity(const vec3& point, const vec3& direction) const {
		return dot(point - origin, direction) >= 0.0f ? intensity : vec3_0;
	}
};

float focal_distance_from_fov(const float fov_degrees) {
	const float half_fov = fov_degrees / 360.0f * pi;
	return std::tan(0.5f*pi - half_fov);
}

struct Camera {
	vec3 origin;
	mat3 orientation;
	float focal_length; // distance from image plane

	Camera(vec3 origin, mat3 orientation, float vertical_fov)
		: origin(origin), orientation(orientation), focal_length(focal_distance_from_fov(vertical_fov))
	{}

	Ray createRay(const vec2 film_pos) const {
		const vec3 cameraspace_ray = mvec3(film_pos[0], film_pos[1], focal_length);
		return Ray{origin, orientation * cameraspace_ray};
	}
};

struct Scene {
	Camera camera;
	std::vector<SceneObject> objects;
	std::vector<SceneLight> lights;

	Scene(Camera camera)
		: camera(camera)
	{}

	Scene(Scene&& o)
		: camera(std::move(o.camera)), objects(std::move(o.objects)), lights(std::move(o.lights))
	{}

private:
	NONCOPYABLE(Scene);
};

Scene setup_scene() {
	const auto black = std::make_shared<TextureSolid>(vec3_0);
	const auto white = std::make_shared<TextureSolid>(vec3_1);
	const auto red = std::make_shared<TextureSolid>(vec3_x);

	Scene s(Camera(vec3_y * 0.2, orient(vec3_y, -vec3_z), 75.0f));
	s.objects.push_back(SceneObject(
		Material(black, std::make_shared<TextureSolid>(1.0f, 0.4f, 0.4f)),
		std::make_unique<ShapeSphere>(TransformPair().translate(mvec3(0.0f, 0.0f, -5.0f)))
		));
	s.objects.push_back(SceneObject(
		Material(white, black),
		std::make_unique<ShapeSphere>(TransformPair().scale(0.25f).translate(mvec3(-0.5f, 1.5f, -3.0f)))
		));

	const mat<2, 4> plane_tex_mapping = {{
		1, 0, 0, 0,
		0, 0, 1, 0
	}};
	const auto checkerboard = std::make_shared<TextureCheckerboard>(white, red);

	s.objects.push_back(SceneObject(
		Material(std::make_shared<TexMapFromPosition>(checkerboard, plane_tex_mapping), white),
		std::make_unique<ShapePlane>(TransformPair().translate(vec3_y * -1.0f))
		));

	s.lights.push_back(SceneLight(mvec3(-2.0f, 4.0f, -4.0f), vec3_1 * 80, 0.25f));

	return std::move(s);
}

static vec2 filmspace_from_screenspace(const vec2 screen_pos, const vec2 screen_size) {
	return (screen_pos - (screen_size * 0.5f)) * 2.0f * (1.0f / screen_size[1]);
}

Optional<Intersection> find_nearest_intersection(const Scene& scene, const Ray ray) {
	Optional<Intersection> nearest_intersection;

	for (const SceneObject& object : scene.objects) {
		const Optional<Intersection> intersection = object.shape->intersect(ray);
		if (intersection && (!nearest_intersection || intersection->t < nearest_intersection->t)) {
			nearest_intersection = intersection;
			nearest_intersection->object = &object;
			nearest_intersection->shape = object.shape.get();
		}
	}

	return nearest_intersection;
}

bool find_any_intersection(const Scene& scene, const Ray& ray, float max_t) {
	for (const SceneObject& object : scene.objects) {
		if (object.shape->hasIntersection(ray, max_t)) {
			return true;
		}
	}

	return false;
}

vec3 reflect(const vec3& l, const vec3& n) {
	return l + 2*dot(n, -l) * n;
}

static const float RAY_EPSILON = 1e-6f;

vec3 lambert_brdf(const vec3& albedo, const vec3& light_dir, const vec3& normal) {
	return albedo * std::max(0.0f, dot(light_dir, normal));
}

vec3 calc_light_incidence(const Scene& scene, Rng& rng, const Ray& ray, int remaining_depth) {
	vec3 color = vec3_0;

	const Optional<Intersection> surface_hit = find_nearest_intersection(scene, ray);
	if (surface_hit) {
		const vec3 albedo = surface_hit->object->material.diffuse->getValue(*surface_hit);

		for (const SceneLight& light : scene.lights) {
			const int NUM_LIGHT_SAMPLES = 500;
			vec3 light_contribution = vec3_0;

			for (int sample = 0; sample < NUM_LIGHT_SAMPLES; ++sample) {
				const LightSample light_sample = light.samplePoint(rng);
				const vec3 light_vec = light_sample.point - surface_hit->position;

				if (!find_any_intersection(scene, Ray{surface_hit->position + surface_hit->normal * RAY_EPSILON, light_vec}, 1.0f)) {
					const vec3 reflectance = lambert_brdf(albedo, normalized(light_vec), surface_hit->normal);
					const vec3 illuminance = light.calcIntensity(light_sample.point, -light_vec) * (1.0f / length_sqr(light_vec));
					light_contribution += reflectance * illuminance * (1.0f / light_sample.pdf);
				}
			}
			color += light_contribution * (1.0f / NUM_LIGHT_SAMPLES);
		}

		const vec3 specular_reflectance = surface_hit->object->material.specular->getValue(*surface_hit);
		if (remaining_depth > 0 && specular_reflectance != vec3_0) {
			color += specular_reflectance * calc_light_incidence(scene, rng, Ray{surface_hit->position + surface_hit->normal * RAY_EPSILON, reflect(normalized(ray.direction), surface_hit->normal)}, remaining_depth-1);
		} else {
			color += specular_reflectance * 0.5f;
		}
	} else {
		color = vec3_0;
	}

	return color;
}

int main(int, char* []) {
	static const int IMAGE_WIDTH = 640;
	static const int IMAGE_HEIGHT = 480;
	std::vector<vec3> image_data(IMAGE_WIDTH * IMAGE_HEIGHT);

	const Scene scene = setup_scene();
	Rng rng;

	for (int y = 0; y < IMAGE_HEIGHT; ++y) {
		for (int x = 0; x < IMAGE_WIDTH; x++) {
			const vec2 film_coord = filmspace_from_screenspace(mvec2(float(x), float(y)), mvec2(float(IMAGE_WIDTH), float(IMAGE_HEIGHT))) * mvec2(1.0f, -1.0f);
			const Ray camera_ray = scene.camera.createRay(film_coord);

			image_data[y*IMAGE_WIDTH + x] = calc_light_incidence(scene, rng, camera_ray, 5);
		}
		std::cout << (y * 100.0f / (IMAGE_HEIGHT-1)) << "%\n";
	}

	save_srgb_image(image_data, IMAGE_WIDTH, IMAGE_HEIGHT);
}
<|endoftext|>


<commit_before>#include <map>
#include <unordered_map>
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <tuple>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <conio.h>				//_getch()

#include "WinDivert-1.1.6-MSVC/include/windivert.h"
#include "ipredir.h"

//quick way to link with WinDivert.lib without changing project settings
#pragma comment(lib, "WinDivert-1.1.6-MSVC/x86/WinDivert")

//lol global variables!!!
ipmap_t ipmap;	//oldip->newip mapping
int dbg = 0;	//debug flag

int main(int argc, char* argv[]) {
	if (argc == 1) {
		usage(argv[0]);
		return 0;
	}

	//list of ips which will be monitored by WinDivert (outbound and inbound)
	std::vector<std::string> ipsout, ipsin;

	//put args in a string vector for easier handling
	std::vector<std::string> args = std::vector<std::string>(argv, argv+argc);

	//parse args, get ip map and lists of ips. returns debug mode
	dbg = parseArgs(args, ipmap, ipsout, ipsin);

	//write filter string using ip lists
	std::string filter = makeFilter(ipsout, ipsin);

	if (dbg) std::cout << "Filter string: " << std::endl << filter << std::endl;

	//begin WinDivert filter
	HANDLE handle = WinDivertOpen(filter.c_str(), WINDIVERT_LAYER_NETWORK, 0, 0);
	if (handle == INVALID_HANDLE_VALUE) {
		std::cout << "Unable to open filter: #" << GetLastError() << std::endl;
		return 1;
	}

	//increase packet queue+timeout
	if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_LEN, 8192)) {
		std::cout << "Unable to set queue length: #" << GetLastError() << std::endl;
		return 1;
	}
	if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_TIME, 2048)) {
		std::cout << "Unable to set queue timeout: #" << GetLastError() << std::endl;
		return 1;
	}

	//start another thread to monitor packets so that the main thread can wait for keypress
	HANDLE thread = CreateThread(NULL, 1, (LPTHREAD_START_ROUTINE)redirThread, (LPVOID)handle, 0, NULL);
	if (thread == NULL) {
		std::cout << "Unable to start thread: #" << GetLastError() << std::endl;
		return 1;
	}

	//wait for keypress
	std::cout << "Redirecting...press any key to stop" << std::endl;
	_getch();

	//exit nicely
	std::cout << "Closing filter..." << std::endl;
	if (!WinDivertClose(handle)) {
		std::cout << "Unable to close filter: #" << GetLastError() << std::endl;
		return 1;
	}

	WaitForSingleObject(thread, INFINITE);

	return 0;
}

//main worker thread. receives captured packets, possibly modifies, and reinjects them
DWORD redirThread(LPVOID arg) {
	HANDLE handle = (HANDLE)arg;

	unsigned char packet[MAXBUF];
	UINT packet_len;
	WINDIVERT_ADDRESS addr;

	UINT32 from, to;

	PWINDIVERT_TCPHDR ptcphdr;
	PWINDIVERT_UDPHDR pudphdr;
	PWINDIVERT_IPHDR piphdr;

	natmap_t natmap;

	// Main loop:
	while (1)
	{
		// Read a matching packet.
		if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len)) {
			//if main thread closed us down, exit nicely
			if (GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_OPERATION_ABORTED)
				return 0;

			std::cout << "Failed to read packet: #" << GetLastError() << std::endl;
			continue;
		}

		//get pointers to IP and TCP/UDP headers
		WinDivertHelperParsePacket(packet, packet_len, &piphdr, NULL, NULL, NULL, &ptcphdr, &pudphdr, NULL, NULL);

		//outbound packet, change destination address and save nat entry
		if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND) {
			//generate nat tuple
			nattuple_t tup = {
				piphdr->Protocol,
				piphdr->SrcAddr,
				piphdr->DstAddr,
				ptcphdr ? ptcphdr->SrcPort : (pudphdr ? pudphdr->SrcPort : 0),
				ptcphdr ? ptcphdr->DstPort : (pudphdr ? pudphdr->DstPort : 0),
			};

			if (dbg) std::cout << "Tx:  " << DisplayTuple(tup) << "->";

			//grab destination ip from header
			from = piphdr->DstAddr;

			//look it up in redirect map
			ipmap_t::iterator iter = ipmap.find(from);
			//if not found, inject unmodified packet (shouldn't happen for outgoing packets since
			//WinDivert only captures ones that we should be redirecting, but meh)
			if (iter == ipmap.end()) {
				if (dbg) std::cout << "X" << std::endl;
				goto outputpacket;	//goto is best way to "break" nested ifs
			}
			to = iter->second;

			if (dbg) std::cout << DottedIPv4(to) << std::endl;

			//replace with new destination ip
			piphdr->DstAddr = to;
			//modify nat tuple also
			tup.remoteip = to;

			//insert nat tuple into nat map
			natmap[tup] = from;	//lookup will give us original ip
			if (dbg) std::cout << "NAT: " << DisplayTuple(tup) << "->" << DottedIPv4(from) << std::endl;
		}

		//inbound packet, get nat tuple and look it up
		else {
			//generate nat tuple
			nattuple_t tup = {
				piphdr->Protocol,
				piphdr->DstAddr,
				piphdr->SrcAddr,
				ptcphdr ? ptcphdr->DstPort : (pudphdr ? pudphdr->DstPort : 0),
				ptcphdr ? ptcphdr->SrcPort : (pudphdr ? pudphdr->SrcPort : 0),
			};

			if (dbg) std::cout << "Rx:  " << DisplayTuple(tup) << "->";

			//look up tuple in nat map
			natmap_t::iterator iter = natmap.find(tup);
			//if nat entry not found, inject unmodified packet (would happen if directly connecting
			//to a server which happens to be a redirect destination)
			if (iter == natmap.end()) {
				if (dbg) std::cout << "X" << std::endl;
				goto outputpacket;	//goto is best way to "break" nested ifs
			}
			to = iter->second;

			if (dbg) std::cout << DottedIPv4(to) << std::endl;

			//replace with original remote ip
			piphdr->SrcAddr = to;
		}

		//jumped to if packet is unmodified
		outputpacket:

		//recalculate checksums
		WinDivertHelperCalcChecksums(packet, packet_len, 0);

		//re-inject the packet
		if (!WinDivertSend(handle, packet, packet_len, &addr, NULL)) {
			std::cout << "Failed to re-inject packet: #" << GetLastError() << std::endl;
		}
	}
}

//given outbound/inbound lists of ips, make a WinDivert filter
std::string makeFilter(std::vector<std::string> ipsout, std::vector<std::string> ipsin) {
	std::vector<std::string>::iterator iter;

	//"(outbound and (ip.SrcAddr==w.x.y.z or ip.SrcAddr==t.u.v.w or false)) or (inbound and (ip.SrcAddr==a.b.c.d or ip.SrcAddr==e.f.g.h or false))"

	std::string filter = "(outbound and (";

	for (iter = ipsout.begin(); iter != ipsout.end(); ++iter) {
		filter += ("ip.DstAddr == " + *iter + " or ");
	}

	filter += "false)) or (inbound and (";

	for (iter = ipsin.begin(); iter != ipsin.end(); ++iter) {
		filter += ("ip.SrcAddr == " + *iter + " or ");
	}

	filter += "false))";

	return filter;
}

//parse argument string and return various info
int parseArgs(std::vector<std::string> args, ipmap_t& ipmap, std::vector<std::string>& ipsout, std::vector<std::string>& ipsin) {
	UINT32 to, from;
	std::string strto, strfrom;
	std::string::size_type eq, comma;
	int dbg = 0;

	std::vector<std::string>::iterator iter;
	for (iter = args.begin(); iter != args.end(); ++iter) {
		std::string arg = *iter;

		//handle simple debug flag
		if (arg == "-d") {
			dbg = 1;
			continue;
		}

		eq = arg.find('=');
		//skip if no equals
		if (eq == std::string::npos)
			continue;

		//store 'to' ip
		strto = arg.substr(eq+1);
		if (!WinDivertHelperParseIPv4Address(strto.c_str(), &to)) {
			std::cout << "Unable to parse ip " << strto << ": #" << GetLastError() << std::endl;
			continue;
		}
		//save string form of 'to' ip to add to WinDivert filter
		ipsin.push_back(strto);
		to = byteswap(to);

		//remove from string
		arg = arg.substr(0, eq);

		//start parsing 'from' ips
		comma = arg.find(',');
		while (1) {
			strfrom = arg.substr(0, comma);
			//save each 'from' ip with associated 'to' ip
			if (WinDivertHelperParseIPv4Address(strfrom.c_str(), &from)) {
				from = byteswap(from);
				ipmap[from] = to;

				//save string form of 'from' ip to add to WinDivert filter
				ipsout.push_back(strfrom);
				std::cout << "Adding redirect from " << strfrom << " to " << strto << std::endl;
			} else {
				std::cout << "Unable to parse ip " << strfrom << ": #" << GetLastError() << std::endl;
			}

			//go to next 'from' ip
			if (comma == std::string::npos)
				break;
			arg = arg.substr(comma+1);
			comma = arg.find(',');
		}
	}

	return dbg;
}

//short byteswap
UINT16 byteswap(UINT16 i) {
	UINT16 o;
	UINT8* pi = (UINT8*)&i;
	UINT8* po = (UINT8*)&o;

	po[0] = pi[1];
	po[1] = pi[0];

	return o;
}
//int byteswap
UINT32 byteswap(UINT32 i) {
	UINT32 o;
	UINT8* pi = (UINT8*)&i;
	UINT8* po = (UINT8*)&o;

	po[0] = pi[3];
	po[1] = pi[2];
	po[2] = pi[1];
	po[3] = pi[0];

	return o;
}

//converts big endian formatted 32bit ip into dotted decimal string form
std::string DottedIPv4(UINT32 ip) {
	std::stringstream ss;
	UINT8* pip = (UINT8*)&ip;
	ss << (int)pip[0] << "." << (int)pip[1] << "." << (int)pip[2] << "." << (int)pip[3];
	return ss.str();
}

//return a name for a protocol id
std::string ProtocolName(UINT8 prot) {
	switch (prot) {
		case 0x01: return "ICMP";
		case 0x06: return "TCP";
		case 0x11: return "UDP";
		default: {
			std::stringstream ss;
			ss << "0x" << std::hex << (int)prot;
			return ss.str();
		}
	};
}

//converts nat tuple into string form
std::string DisplayTuple(nattuple_t o) {
	std::stringstream ss;
	ss << "(P: " << ProtocolName(o.protocol) << ", LIP: " << DottedIPv4(o.localip) << ", RIP: " << DottedIPv4(o.remoteip);
	if (o.localport) ss << ", Lp: " << byteswap(o.localport);
	if (o.remoteport) ss << ", Rp: " << byteswap(o.remoteport);
	ss << ")";
	return ss.str();
}

//show usage/help
void usage(const char* arg) {
	std::cout << "ipredir by cybermind" << std::endl;
	std::cout << "Will rewrite outgoing packets to redirect which IP they are headed to." << std::endl;
	std::cout << "It will also rewrite the incoming packets back to their original values," << std::endl;
	std::cout << "acting as a rudimentary NAT." << std::endl;
	std::cout << std::endl;
	std::cout << "Usage:" << std::endl;
	std::cout << "\t" << arg << " <rule> [rule...]" << std::endl;
	std::cout << std::endl;
	std::cout << "A rule is of the format:" << std::endl;
	std::cout << "\toldip[,oldip[,oldip[...]]]=newip" << std::endl;
	std::cout << std::endl;
	std::cout << "where any packets headed for 'oldip' will be redirected to 'newip'" << std::endl;
	std::cout << std::endl;
	std::cout << "Examples:" << std::endl;
	std::cout << "\t" << arg << " 1.2.3.4=192.168.1.1" << std::endl;
	std::cout << "\t" << arg << " 1.2.3.4,1.2.3.5=192.168.1.1" << std::endl;
	std::cout << "\t" << arg << " 1.2.3.4,1.2.3.5=192.168.1.1 2.3.4.5=192.168.2.1" << std::endl;
}
<commit_msg>Added versioning<commit_after>#include <map>
#include <unordered_map>
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <tuple>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <conio.h>				//_getch()

#include "WinDivert-1.1.6-MSVC/include/windivert.h"
#include "ipredir.h"

//quick way to link with WinDivert.lib without changing project settings
#pragma comment(lib, "WinDivert-1.1.6-MSVC/x86/WinDivert")

const int VERSION_MAJOR = 1;
const int VERSION_MINOR = 0;
const int VERSION_PATCH = 0;
const std::string VERSION_STR = "v" + std::to_string(VERSION_MAJOR) + "." + std::to_string(VERSION_MINOR) + "." + std::to_string(VERSION_PATCH);

//lol global variables!!!
ipmap_t ipmap;	//oldip->newip mapping
int dbg = 0;	//debug flag

int main(int argc, char* argv[]) {
	if (argc == 1) {
		usage(argv[0]);
		return 0;
	}

	//list of ips which will be monitored by WinDivert (outbound and inbound)
	std::vector<std::string> ipsout, ipsin;

	//put args in a string vector for easier handling
	std::vector<std::string> args = std::vector<std::string>(argv, argv+argc);

	//parse args, get ip map and lists of ips. returns debug mode
	dbg = parseArgs(args, ipmap, ipsout, ipsin);

	//write filter string using ip lists
	std::string filter = makeFilter(ipsout, ipsin);

	if (dbg) std::cout << "Filter string: " << std::endl << filter << std::endl;

	//begin WinDivert filter
	HANDLE handle = WinDivertOpen(filter.c_str(), WINDIVERT_LAYER_NETWORK, 0, 0);
	if (handle == INVALID_HANDLE_VALUE) {
		std::cout << "Unable to open filter: #" << GetLastError() << std::endl;
		return 1;
	}

	//increase packet queue+timeout
	if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_LEN, 8192)) {
		std::cout << "Unable to set queue length: #" << GetLastError() << std::endl;
		return 1;
	}
	if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_TIME, 2048)) {
		std::cout << "Unable to set queue timeout: #" << GetLastError() << std::endl;
		return 1;
	}

	//start another thread to monitor packets so that the main thread can wait for keypress
	HANDLE thread = CreateThread(NULL, 1, (LPTHREAD_START_ROUTINE)redirThread, (LPVOID)handle, 0, NULL);
	if (thread == NULL) {
		std::cout << "Unable to start thread: #" << GetLastError() << std::endl;
		return 1;
	}

	//wait for keypress
	std::cout << "Redirecting...press any key to stop" << std::endl;
	_getch();

	//exit nicely
	std::cout << "Closing filter..." << std::endl;
	if (!WinDivertClose(handle)) {
		std::cout << "Unable to close filter: #" << GetLastError() << std::endl;
		return 1;
	}

	WaitForSingleObject(thread, INFINITE);

	return 0;
}

//main worker thread. receives captured packets, possibly modifies, and reinjects them
DWORD redirThread(LPVOID arg) {
	HANDLE handle = (HANDLE)arg;

	unsigned char packet[MAXBUF];
	UINT packet_len;
	WINDIVERT_ADDRESS addr;

	UINT32 from, to;

	PWINDIVERT_TCPHDR ptcphdr;
	PWINDIVERT_UDPHDR pudphdr;
	PWINDIVERT_IPHDR piphdr;

	natmap_t natmap;

	// Main loop:
	while (1)
	{
		// Read a matching packet.
		if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len)) {
			//if main thread closed us down, exit nicely
			if (GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_OPERATION_ABORTED)
				return 0;

			std::cout << "Failed to read packet: #" << GetLastError() << std::endl;
			continue;
		}

		//get pointers to IP and TCP/UDP headers
		WinDivertHelperParsePacket(packet, packet_len, &piphdr, NULL, NULL, NULL, &ptcphdr, &pudphdr, NULL, NULL);

		//outbound packet, change destination address and save nat entry
		if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND) {
			//generate nat tuple
			nattuple_t tup = {
				piphdr->Protocol,
				piphdr->SrcAddr,
				piphdr->DstAddr,
				ptcphdr ? ptcphdr->SrcPort : (pudphdr ? pudphdr->SrcPort : 0),
				ptcphdr ? ptcphdr->DstPort : (pudphdr ? pudphdr->DstPort : 0),
			};

			if (dbg) std::cout << "Tx:  " << DisplayTuple(tup) << "->";

			//grab destination ip from header
			from = piphdr->DstAddr;

			//look it up in redirect map
			ipmap_t::iterator iter = ipmap.find(from);
			//if not found, inject unmodified packet (shouldn't happen for outgoing packets since
			//WinDivert only captures ones that we should be redirecting, but meh)
			if (iter == ipmap.end()) {
				if (dbg) std::cout << "X" << std::endl;
				goto outputpacket;	//goto is best way to "break" nested ifs
			}
			to = iter->second;

			if (dbg) std::cout << DottedIPv4(to) << std::endl;

			//replace with new destination ip
			piphdr->DstAddr = to;
			//modify nat tuple also
			tup.remoteip = to;

			//insert nat tuple into nat map
			natmap[tup] = from;	//lookup will give us original ip
			if (dbg) std::cout << "NAT: " << DisplayTuple(tup) << "->" << DottedIPv4(from) << std::endl;
		}

		//inbound packet, get nat tuple and look it up
		else {
			//generate nat tuple
			nattuple_t tup = {
				piphdr->Protocol,
				piphdr->DstAddr,
				piphdr->SrcAddr,
				ptcphdr ? ptcphdr->DstPort : (pudphdr ? pudphdr->DstPort : 0),
				ptcphdr ? ptcphdr->SrcPort : (pudphdr ? pudphdr->SrcPort : 0),
			};

			if (dbg) std::cout << "Rx:  " << DisplayTuple(tup) << "->";

			//look up tuple in nat map
			natmap_t::iterator iter = natmap.find(tup);
			//if nat entry not found, inject unmodified packet (would happen if directly connecting
			//to a server which happens to be a redirect destination)
			if (iter == natmap.end()) {
				if (dbg) std::cout << "X" << std::endl;
				goto outputpacket;	//goto is best way to "break" nested ifs
			}
			to = iter->second;

			if (dbg) std::cout << DottedIPv4(to) << std::endl;

			//replace with original remote ip
			piphdr->SrcAddr = to;
		}

		//jumped to if packet is unmodified
		outputpacket:

		//recalculate checksums
		WinDivertHelperCalcChecksums(packet, packet_len, 0);

		//re-inject the packet
		if (!WinDivertSend(handle, packet, packet_len, &addr, NULL)) {
			std::cout << "Failed to re-inject packet: #" << GetLastError() << std::endl;
		}
	}
}

//given outbound/inbound lists of ips, make a WinDivert filter
std::string makeFilter(std::vector<std::string> ipsout, std::vector<std::string> ipsin) {
	std::vector<std::string>::iterator iter;

	//"(outbound and (ip.SrcAddr==w.x.y.z or ip.SrcAddr==t.u.v.w or false)) or (inbound and (ip.SrcAddr==a.b.c.d or ip.SrcAddr==e.f.g.h or false))"

	std::string filter = "(outbound and (";

	for (iter = ipsout.begin(); iter != ipsout.end(); ++iter) {
		filter += ("ip.DstAddr == " + *iter + " or ");
	}

	filter += "false)) or (inbound and (";

	for (iter = ipsin.begin(); iter != ipsin.end(); ++iter) {
		filter += ("ip.SrcAddr == " + *iter + " or ");
	}

	filter += "false))";

	return filter;
}

//parse argument string and return various info
int parseArgs(std::vector<std::string> args, ipmap_t& ipmap, std::vector<std::string>& ipsout, std::vector<std::string>& ipsin) {
	UINT32 to, from;
	std::string strto, strfrom;
	std::string::size_type eq, comma;
	int dbg = 0;

	std::vector<std::string>::iterator iter;
	for (iter = args.begin(); iter != args.end(); ++iter) {
		std::string arg = *iter;

		//handle simple debug flag
		if (arg == "-d") {
			dbg = 1;
			continue;
		}

		eq = arg.find('=');
		//skip if no equals
		if (eq == std::string::npos)
			continue;

		//store 'to' ip
		strto = arg.substr(eq+1);
		if (!WinDivertHelperParseIPv4Address(strto.c_str(), &to)) {
			std::cout << "Unable to parse ip " << strto << ": #" << GetLastError() << std::endl;
			continue;
		}
		//save string form of 'to' ip to add to WinDivert filter
		ipsin.push_back(strto);
		to = byteswap(to);

		//remove from string
		arg = arg.substr(0, eq);

		//start parsing 'from' ips
		comma = arg.find(',');
		while (1) {
			strfrom = arg.substr(0, comma);
			//save each 'from' ip with associated 'to' ip
			if (WinDivertHelperParseIPv4Address(strfrom.c_str(), &from)) {
				from = byteswap(from);
				ipmap[from] = to;

				//save string form of 'from' ip to add to WinDivert filter
				ipsout.push_back(strfrom);
				std::cout << "Adding redirect from " << strfrom << " to " << strto << std::endl;
			} else {
				std::cout << "Unable to parse ip " << strfrom << ": #" << GetLastError() << std::endl;
			}

			//go to next 'from' ip
			if (comma == std::string::npos)
				break;
			arg = arg.substr(comma+1);
			comma = arg.find(',');
		}
	}

	return dbg;
}

//short byteswap
UINT16 byteswap(UINT16 i) {
	UINT16 o;
	UINT8* pi = (UINT8*)&i;
	UINT8* po = (UINT8*)&o;

	po[0] = pi[1];
	po[1] = pi[0];

	return o;
}
//int byteswap
UINT32 byteswap(UINT32 i) {
	UINT32 o;
	UINT8* pi = (UINT8*)&i;
	UINT8* po = (UINT8*)&o;

	po[0] = pi[3];
	po[1] = pi[2];
	po[2] = pi[1];
	po[3] = pi[0];

	return o;
}

//converts big endian formatted 32bit ip into dotted decimal string form
std::string DottedIPv4(UINT32 ip) {
	std::stringstream ss;
	UINT8* pip = (UINT8*)&ip;
	ss << (int)pip[0] << "." << (int)pip[1] << "." << (int)pip[2] << "." << (int)pip[3];
	return ss.str();
}

//return a name for a protocol id
std::string ProtocolName(UINT8 prot) {
	switch (prot) {
		case 0x01: return "ICMP";
		case 0x06: return "TCP";
		case 0x11: return "UDP";
		default: {
			std::stringstream ss;
			ss << "0x" << std::hex << (int)prot;
			return ss.str();
		}
	};
}

//converts nat tuple into string form
std::string DisplayTuple(nattuple_t o) {
	std::stringstream ss;
	ss << "(P: " << ProtocolName(o.protocol) << ", LIP: " << DottedIPv4(o.localip) << ", RIP: " << DottedIPv4(o.remoteip);
	if (o.localport) ss << ", Lp: " << byteswap(o.localport);
	if (o.remoteport) ss << ", Rp: " << byteswap(o.remoteport);
	ss << ")";
	return ss.str();
}

//show usage/help
void usage(const char* arg) {
	std::cout << "ipredir " << VERSION_STR << " by cybermind" << std::endl;
	std::cout << "Will rewrite outgoing packets to redirect which IP they are headed to." << std::endl;
	std::cout << "It will also rewrite the incoming packets back to their original values," << std::endl;
	std::cout << "acting as a rudimentary NAT." << std::endl;
	std::cout << std::endl;
	std::cout << "Usage:" << std::endl;
	std::cout << "\t" << arg << " <rule> [rule...]" << std::endl;
	std::cout << std::endl;
	std::cout << "A rule is of the format:" << std::endl;
	std::cout << "\toldip[,oldip[,oldip[...]]]=newip" << std::endl;
	std::cout << std::endl;
	std::cout << "where any packets headed for 'oldip' will be redirected to 'newip'" << std::endl;
	std::cout << std::endl;
	std::cout << "Examples:" << std::endl;
	std::cout << "\t" << arg << " 1.2.3.4=192.168.1.1" << std::endl;
	std::cout << "\t" << arg << " 1.2.3.4,1.2.3.5=192.168.1.1" << std::endl;
	std::cout << "\t" << arg << " 1.2.3.4,1.2.3.5=192.168.1.1 2.3.4.5=192.168.2.1" << std::endl;
}
<|endoftext|>


<commit_before>/* zwc - a filter for counting words in a FASTA file
 * author - Zebulun Arendsee
 *
 * $ wordcount 2 < sample.faa
 * CA	3
 * AA	3
 * TA	2
 * GA	1
 * TG	1
 * GT	1
 * AT	3
 * CG	1
 * AC	4
 */

#include <unordered_map>
#include <string>
#include <iostream>

int main(int argc, char ** argv){
    int k = 1;

    if (argc == 2){
        k = atoi(argv[1]);
    }

    std::string word = std::string(k, 'x');

    typedef std::unordered_map<std::string, int> hashmap;
    hashmap counts;

    int seqpos = 0;
    bool is_header = false;
    char c;
    while((c = fgetc(stdin)) != EOF){
        switch (c) {
            case '>':
                is_header = true;
                seqpos = 0;
                break;
            case '\n':
                if(is_header){
                    is_header = false;
                }
                break;
            default:
                if(is_header)
                    break;
                seqpos++;
                for(int j = 0; j < (k-1); j++){
                    word[j] = word[j + 1];
                }
                word[k-1] = c;
                if(seqpos >= k){
                    counts[word]++;
                }
                break;
        }
    }

    for(hashmap::iterator it = counts.begin(); it != counts.end(); it++) {
        printf("%s\t%d\n", it->first.c_str(), it->second);
    }

    return 0;
}
<commit_msg>Require reading from a named file -- 5s<commit_after>/* zwc - a filter for counting words in a FASTA file
 * author - Zebulun Arendsee
 *
 * $ wordcount 2 < sample.faa
 * CA	3
 * AA	3
 * TA	2
 * GA	1
 * TG	1
 * GT	1
 * AT	3
 * CG	1
 * AC	4
 */

#include <unordered_map>
#include <string>
#include <stdio.h>

int main(int argc, char ** argv){
    int k = 1;
    FILE* fh;

    if(argc > 1){
        k  = atoi(argv[1]);
        if (argc == 3){
            fh = fopen(argv[2], "r");
        } else {
            fh = stdin;
        }
    } else {
        return 1;
    }

    std::string word = std::string(k, 'x');

    typedef std::unordered_map<std::string, int> hashmap;
    hashmap counts;

    int seqpos = 0;
    bool is_header = false;
    char c;
    while((c = fgetc(fh)) != EOF){
        switch (c) {
            case '>':
                is_header = true;
                seqpos = 0;
                break;
            case '\n':
                if(is_header){
                    is_header = false;
                }
                break;
            default:
                if(is_header)
                    break;
                seqpos++;
                for(int j = 0; j < (k-1); j++){
                    word[j] = word[j + 1];
                }
                word[k-1] = c;
                if(seqpos >= k){
                    counts[word]++;
                }
                break;
        }
    }

    for(hashmap::iterator it = counts.begin(); it != counts.end(); it++) {
        printf("%s\t%d\n", it->first.c_str(), it->second);
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>

#include <unordered_map>
#include <atomic>
#include <string>

#include <dlfcn.h>
#include <unistd.h>

#define UNW_LOCAL_ONLY
#include <libunwind.h>

using namespace std;

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;

struct IPCacheEntry
{
    size_t id;
    bool skip;
    bool stop;
};

atomic<size_t> next_cache_id;
atomic<size_t> next_thread_id;

// must be kept separately from ThreadData to ensure it stays valid
// even until after ThreadData is destroyed
thread_local bool in_handler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

//TODO: per-thread output
struct ThreadData
{
    ThreadData()
        : thread_id(next_thread_id++)
        , out(nullptr)
    {
        bool wasInHandler = in_handler;
        in_handler = true;
        ipCache.reserve(1024);
        string outputFileName = env("DUMP_MALLOC_TRACE_OUTPUT") + to_string(getpid()) + '.' + to_string(thread_id);
        out = fopen(outputFileName.c_str(), "wa");
        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }
        in_handler = wasInHandler;
    }

    ~ThreadData()
    {
        in_handler = true;
        fclose(out);
    }

    unordered_map<unw_word_t, IPCacheEntry> ipCache;
    size_t thread_id;
    FILE* out;
};

thread_local ThreadData threadData;

void print_caller()
{
    unw_context_t uc;
    unw_getcontext (&uc);

    unw_cursor_t cursor;
    unw_init_local (&cursor, &uc);

    // skip handleMalloc & malloc
    for (int i = 0; i < 2; ++i) {
        if (unw_step(&cursor) <= 0) {
            return;
        }
    }

    auto& ipCache = threadData.ipCache;

    while (unw_step(&cursor) > 0)
    {
        unw_word_t ip;
        unw_get_reg(&cursor, UNW_REG_IP, &ip);

        // check cache for known ip's
        auto it = ipCache.find(ip);
        if (it == ipCache.end()) {
            // not cached yet, get data
            const size_t BUF_SIZE = 256;
            char name[BUF_SIZE];
            name[0] = '\0';
            unw_word_t offset;
            unw_get_proc_name(&cursor, name, BUF_SIZE, &offset);
            // skip operator new (_Znwm) and operator new[] (_Znam)
            const bool skip = name[0] == '_' && name[1] == 'Z' && name[2] == 'n'
                        && name[4] == 'm' && name[5] == '\0'
                        && (name[3] == 'w' || name[3] == 'a');
            const bool stop = !skip && (!strcmp(name, "main")
                                    || !strcmp(name, "_GLOBAL__sub_I_main")
                                    || !strcmp(name, "_Z41__static_initialization_and_destruction_0ii"));
            const size_t id = next_cache_id++;

            // and store it in the cache
            ipCache.insert(it, make_pair(ip, IPCacheEntry{id, skip, stop}));

            if (!skip) {
                fprintf(threadData.out, "%lu=%lx@%s+0x%lx;", id, ip, name, offset);
            }
            if (stop) {
                break;
            }
            continue;
        }

        const auto& frame = it->second;
        if (!frame.skip) {
            fprintf(threadData.out, "%lu;", frame.id);
        }
        if (frame.stop) {
            break;
        }
    }
}

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "could not find original function %s\n", name);
        exit(1);
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        exit(1);
    }
    return buf + oldOffset;
}

void init()
{
    if (in_handler) {
        fprintf(stderr, "initialization recursion detected\n");
        exit(1);
    }

    in_handler = true;

    real_calloc = &dummy_calloc;
    real_calloc = findReal<calloc_t>("calloc");
    real_malloc = findReal<malloc_t>("malloc");
    real_free = findReal<free_t>("free");
    real_realloc = findReal<realloc_t>("realloc");
    real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
    real_valloc = findReal<valloc_t>("valloc");
    real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

    in_handler = false;
}

void handleMalloc(void* ptr, size_t size)
{
    fprintf(threadData.out, "+%ld:%p ", size, ptr);
    print_caller();
    fprintf(threadData.out,"\n");
}

void handleFree(void* ptr)
{
    fprintf(threadData.out, "-%p\n", ptr);
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    real_free(ptr);

    if (!in_handler) {
        in_handler = true;
        handleFree(ptr);
        in_handler = false;
    }
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (!in_handler) {
        in_handler = true;
        handleFree(ptr);
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, num*size);
        in_handler = false;
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(*memptr, size);
        in_handler = false;
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

}
<commit_msg>Only print a given call-tree once<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>

#include <unordered_map>
#include <atomic>
#include <string>
#include <vector>

#include <boost/functional/hash.hpp>

#include <dlfcn.h>
#include <unistd.h>

#define UNW_LOCAL_ONLY
#include <libunwind.h>

using namespace std;

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;

struct IPCacheEntry
{
    size_t id;
    bool skip;
    bool stop;
};

atomic<size_t> next_cache_id;
atomic<size_t> next_thread_id;

// must be kept separately from ThreadData to ensure it stays valid
// even until after ThreadData is destroyed
thread_local bool in_handler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

struct Tree
{
    static const size_t MAX_DEPTH = 64;
    size_t data[MAX_DEPTH];
    size_t depth;

    bool operator==(const Tree& o) const
    {
        return depth == o.depth && !memcmp(data, o.data, sizeof(size_t) * depth);
    }
};

struct TreeHasher
{
    size_t operator()(const Tree& tree) const
    {
        size_t seed = 0;
        hash<size_t> nodeHash;
        for (size_t i = 0; i < tree.depth; ++i) {
            boost::hash_combine(seed, nodeHash(tree.data[i]));
        }
        return seed;
    }
};

//TODO: merge per-thread output into single file
struct ThreadData
{
    ThreadData()
        : thread_id(next_thread_id++)
        , out(nullptr)
    {
        bool wasInHandler = in_handler;
        in_handler = true;
        ipCache.reserve(1024);
        string outputFileName = env("DUMP_MALLOC_TRACE_OUTPUT") + to_string(getpid()) + '.' + to_string(thread_id);
        out = fopen(outputFileName.c_str(), "wa");
        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }
        in_handler = wasInHandler;
    }

    ~ThreadData()
    {
        in_handler = true;
        fclose(out);
    }

    unordered_map<unw_word_t, IPCacheEntry> ipCache;
    unordered_map<Tree, size_t, TreeHasher> treeCache;
    size_t thread_id;
    FILE* out;
};

thread_local ThreadData threadData;

size_t print_caller()
{
    unw_context_t uc;
    unw_getcontext (&uc);

    unw_cursor_t cursor;
    unw_init_local (&cursor, &uc);

    // skip handleMalloc & malloc
    for (int i = 0; i < 2; ++i) {
        if (unw_step(&cursor) <= 0) {
            return 0;
        }
    }

    auto& ipCache = threadData.ipCache;

    Tree tree;
    tree.depth = 0;
    while (unw_step(&cursor) > 0 && tree.depth < Tree::MAX_DEPTH) {
        unw_word_t ip;
        unw_get_reg(&cursor, UNW_REG_IP, &ip);

        // check cache for known ip's
        auto it = ipCache.find(ip);
        if (it == ipCache.end()) {
            // not cached yet, get data
            const size_t BUF_SIZE = 256;
            char name[BUF_SIZE];
            name[0] = '\0';
            unw_word_t offset;
            unw_get_proc_name(&cursor, name, BUF_SIZE, &offset);
            // skip operator new (_Znwm) and operator new[] (_Znam)
            const bool skip = name[0] == '_' && name[1] == 'Z' && name[2] == 'n'
                        && name[4] == 'm' && name[5] == '\0'
                        && (name[3] == 'w' || name[3] == 'a');
            const bool stop = !skip && (!strcmp(name, "main")
                                    || !strcmp(name, "_GLOBAL__sub_I_main")
                                    || !strcmp(name, "_Z41__static_initialization_and_destruction_0ii"));
            const size_t id = next_cache_id++;

            // and store it in the cache
            it = ipCache.insert(it, make_pair(ip, IPCacheEntry{id, skip, stop}));

            if (!skip) {
                fprintf(threadData.out, "%lu=%lx@%s+0x%lx\n", id, ip, name, offset);
            }
        }

        const auto& frame = it->second;
        if (!frame.skip) {
            tree.data[tree.depth++] = frame.id;
        }
        if (frame.stop) {
            break;
        }
    }

    auto& treeCache = threadData.treeCache;
    auto it = treeCache.find(tree);
    if (it == treeCache.end()) {
        it = treeCache.insert(it, make_pair(tree, next_cache_id++));

        fprintf(threadData.out, "%lu=", it->second);
        for (size_t i = 0; i < tree.depth; ++i) {
            fprintf(threadData.out, "%lu;", tree.data[i]);
        }
        fputs("\n", threadData.out);
    }

    return it->second;
}

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "could not find original function %s\n", name);
        exit(1);
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        exit(1);
    }
    return buf + oldOffset;
}

void init()
{
    if (in_handler) {
        fprintf(stderr, "initialization recursion detected\n");
        exit(1);
    }

    in_handler = true;

    real_calloc = &dummy_calloc;
    real_calloc = findReal<calloc_t>("calloc");
    real_malloc = findReal<malloc_t>("malloc");
    real_free = findReal<free_t>("free");
    real_realloc = findReal<realloc_t>("realloc");
    real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
    real_valloc = findReal<valloc_t>("valloc");
    real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

    in_handler = false;
}

void handleMalloc(void* ptr, size_t size)
{
    const size_t treeId = print_caller();
    fprintf(threadData.out, "+%lu:%p %lu\n", size, ptr, treeId);
}

void handleFree(void* ptr)
{
    fprintf(threadData.out, "-%p\n", ptr);
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    real_free(ptr);

    if (!in_handler) {
        in_handler = true;
        handleFree(ptr);
        in_handler = false;
    }
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (!in_handler) {
        in_handler = true;
        handleFree(ptr);
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, num*size);
        in_handler = false;
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(*memptr, size);
        in_handler = false;
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (!in_handler) {
        in_handler = true;
        handleMalloc(ret, size);
        in_handler = false;
    }

    return ret;
}

}
<|endoftext|>


<commit_before>#include "os.h"
#include "led.h"

using namespace intros;

auto sem = Semaphore::Binary(0);

auto sla = Task::Start([]
{
	sem.wait();
	led_toggle();
});

auto mas = Task::Start([]
{
	this_task::sleepFor(SEC);
	sem.give();
});

int main()
{
	led_init();
	this_task::exit();
}
<commit_msg>updated examples<commit_after>#include "os.h"
#include "led.h"

using namespace intros;

auto sem = Semaphore::Binary(0);

auto sla = Task::Start([]
{
	sem.wait();
	led_toggle();
});

auto mas = Task::Start([]
{
	thisTask::sleepFor(SEC);
	sem.give();
});

int main()
{
	led_init();
	thisTask::exit();
}
<|endoftext|>