<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// This is a GPU-backend specific test. It relies on static intializers to work

#include "SkTypes.h"

#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS

#include "gl/GrGpuGL.h"
#include "GrBackendEffectFactory.h"
#include "GrContextFactory.h"
#include "GrDrawEffect.h"
#include "effects/GrConfigConversionEffect.h"

#include "SkRandom.h"
#include "Test.h"

void GrGLProgram::Desc::setRandom(SkMWCRandom* random,
                                  const GrGpuGL* gpu,
                                  const GrEffectStage stages[GrDrawState::kNumStages]) {
    fAttribBindings = 0;
    fEmitsPointSize = random->nextBool();
    fColorInput = random->nextULessThan(kColorInputCnt);
    fCoverageInput = random->nextULessThan(kColorInputCnt);

    fColorFilterXfermode = random->nextULessThan(SkXfermode::kCoeffModesCnt);

    fFirstCoverageStage = random->nextULessThan(GrDrawState::kNumStages);

    fAttribBindings |= random->nextBool() ? GrDrawState::kCoverage_AttribBindingsBit : 0;

#if GR_GL_EXPERIMENTAL_GS
    fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
#endif

    if (gpu->caps()->shaderDerivativeSupport()) {
        fDiscardIfOutsideEdge = random->nextBool();
    } else {
        fDiscardIfOutsideEdge = false;
    }

    if (gpu->caps()->dualSourceBlendingSupport()) {
        fDualSrcOutput = random->nextULessThan(kDualSrcOutputCnt);
    } else {
        fDualSrcOutput = kNone_DualSrcOutput;
    }

    // use separate tex coords?
    if (random->nextBool()) {
        fAttribBindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
    }

    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
        if (NULL != stages[s].getEffect()) {
            const GrBackendEffectFactory& factory = (*stages[s].getEffect())->getFactory();
            bool explicitLocalCoords = (fAttribBindings &
                                        GrDrawState::kLocalCoords_AttribBindingsBit);
            GrDrawEffect drawEffect(stages[s], explicitLocalCoords);
            fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
        }
    }

    int attributeIndex = 0;
    fPositionAttributeIndex = attributeIndex;
    ++attributeIndex;
    if (fColorInput || (fAttribBindings & GrDrawState::kColor_AttribBindingsBit)) {
        fColorAttributeIndex = attributeIndex;
        ++attributeIndex;
    }
    if (fCoverageInput || (fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit)) {
        fCoverageAttributeIndex = attributeIndex;
        ++attributeIndex;
    }
    if (fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
        fLocalCoordsAttributeIndex = attributeIndex;
        ++attributeIndex;
    }
}

bool GrGpuGL::programUnitTest(int maxStages) {

    maxStages = GrMin(maxStages, (int)GrDrawState::kNumStages);

    GrTextureDesc dummyDesc;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));

    static const int NUM_TESTS = 512;

    SkMWCRandom random;
    for (int t = 0; t < NUM_TESTS; ++t) {

#if 0
        GrPrintf("\nTest Program %d\n-------------\n", t);
        static const int stop = -1;
        if (t == stop) {
            int breakpointhere = 9;
        }
#endif

        GrGLProgram::Desc pdesc;
        GrEffectStage stages[GrDrawState::kNumStages];

        int currAttribIndex = GrDrawState::kAttribIndexCount;
        int attribIndices[2];
        for (int s = 0; s < maxStages; ++s) {
            // enable the stage?
            if (random.nextBool()) {
                GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
                SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
                                                                                &random,
                                                                                this->getContext(),
                                                                                *this->caps(),
                                                                                dummyTextures));
                int numAttribs = (*effect)->numVertexAttribs();

                // If adding this effect would cause to exceed the max attrib count then generate a
                // new random effect. The explanation for why this check is correct is a bit
                // convoluted and this code will be removed soon.
                if (currAttribIndex + numAttribs > GrDrawState::kCoverageOverrideAttribIndexValue) {
                    --s;
                    continue;
                }
                for (int i = 0; i < numAttribs; ++i) {
                    attribIndices[i] = currAttribIndex++;
                }
                stages[s].setEffect(effect.get(), attribIndices[0], attribIndices[1]);
            }
        }
        pdesc.setRandom(&random, this, stages);

        const GrEffectStage* stagePtrs[GrDrawState::kNumStages];
        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
            stagePtrs[s] = &stages[s];
        }
        SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContext(),
                                                              pdesc,
                                                              stagePtrs));
        if (NULL == program.get()) {
            return false;
        }
    }
    return true;
}

static void GLProgramsTest(skiatest::Reporter* reporter, GrContextFactory* factory) {
    for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
        GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
        if (NULL != context) {
            GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
            int maxStages = GrDrawState::kNumStages;
#if SK_ANGLE
            // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
            if (type == GrContextFactory::kANGLE_GLContextType) {
                maxStages = 3;
            }
#endif
            REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
        }
    }
}

#include "TestClassDef.h"
DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)

// This is evil evil evil. The linker may throw away whole translation units as dead code if it
// thinks none of the functions are called. It will do this even if there are static initializers
// in the unit that could pass pointers to functions from the unit out to other translation units!
// We force some of the effects that would otherwise be discarded to link here.

#include "SkLightingImageFilter.h"
#include "SkMagnifierImageFilter.h"
#include "SkColorMatrixFilter.h"

void forceLinking();

void forceLinking() {
    SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
    SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1);
    GrConfigConversionEffect::Create(NULL,
                                     false,
                                     GrConfigConversionEffect::kNone_PMConversion,
                                     SkMatrix::I());
    SkScalar matrix[20];
    SkColorMatrixFilter cmf(matrix);
}

#endif
<commit_msg>Fix unit test build break<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// This is a GPU-backend specific test. It relies on static intializers to work

#include "SkTypes.h"

#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS

#include "gl/GrGpuGL.h"
#include "GrBackendEffectFactory.h"
#include "GrContextFactory.h"
#include "GrDrawEffect.h"
#include "effects/GrConfigConversionEffect.h"

#include "SkRandom.h"
#include "Test.h"

void GrGLProgram::Desc::setRandom(SkMWCRandom* random,
                                  const GrGpuGL* gpu,
                                  const GrEffectStage stages[GrDrawState::kNumStages]) {
    fAttribBindings = 0;
    fEmitsPointSize = random->nextBool();
    fColorInput = random->nextULessThan(kColorInputCnt);
    fCoverageInput = random->nextULessThan(kColorInputCnt);

    fColorFilterXfermode = random->nextULessThan(SkXfermode::kCoeffModesCnt);

    fFirstCoverageStage = random->nextULessThan(GrDrawState::kNumStages);

    fAttribBindings |= random->nextBool() ? GrDrawState::kCoverage_AttribBindingsBit : 0;

#if GR_GL_EXPERIMENTAL_GS
    fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
#endif

    fDiscardIfZeroCoverage = random->nextBool();

    if (gpu->caps()->dualSourceBlendingSupport()) {
        fDualSrcOutput = random->nextULessThan(kDualSrcOutputCnt);
    } else {
        fDualSrcOutput = kNone_DualSrcOutput;
    }

    // use separate tex coords?
    if (random->nextBool()) {
        fAttribBindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
    }

    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
        if (NULL != stages[s].getEffect()) {
            const GrBackendEffectFactory& factory = (*stages[s].getEffect())->getFactory();
            bool explicitLocalCoords = (fAttribBindings &
                                        GrDrawState::kLocalCoords_AttribBindingsBit);
            GrDrawEffect drawEffect(stages[s], explicitLocalCoords);
            fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
        }
    }

    int attributeIndex = 0;
    fPositionAttributeIndex = attributeIndex;
    ++attributeIndex;
    if (fColorInput || (fAttribBindings & GrDrawState::kColor_AttribBindingsBit)) {
        fColorAttributeIndex = attributeIndex;
        ++attributeIndex;
    }
    if (fCoverageInput || (fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit)) {
        fCoverageAttributeIndex = attributeIndex;
        ++attributeIndex;
    }
    if (fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
        fLocalCoordsAttributeIndex = attributeIndex;
        ++attributeIndex;
    }
}

bool GrGpuGL::programUnitTest(int maxStages) {

    maxStages = GrMin(maxStages, (int)GrDrawState::kNumStages);

    GrTextureDesc dummyDesc;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));

    static const int NUM_TESTS = 512;

    SkMWCRandom random;
    for (int t = 0; t < NUM_TESTS; ++t) {

#if 0
        GrPrintf("\nTest Program %d\n-------------\n", t);
        static const int stop = -1;
        if (t == stop) {
            int breakpointhere = 9;
        }
#endif

        GrGLProgram::Desc pdesc;
        GrEffectStage stages[GrDrawState::kNumStages];

        int currAttribIndex = GrDrawState::kAttribIndexCount;
        int attribIndices[2];
        for (int s = 0; s < maxStages; ++s) {
            // enable the stage?
            if (random.nextBool()) {
                GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
                SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
                                                                                &random,
                                                                                this->getContext(),
                                                                                *this->caps(),
                                                                                dummyTextures));
                int numAttribs = (*effect)->numVertexAttribs();

                // If adding this effect would cause to exceed the max attrib count then generate a
                // new random effect. The explanation for why this check is correct is a bit
                // convoluted and this code will be removed soon.
                if (currAttribIndex + numAttribs > GrDrawState::kCoverageOverrideAttribIndexValue) {
                    --s;
                    continue;
                }
                for (int i = 0; i < numAttribs; ++i) {
                    attribIndices[i] = currAttribIndex++;
                }
                stages[s].setEffect(effect.get(), attribIndices[0], attribIndices[1]);
            }
        }
        pdesc.setRandom(&random, this, stages);

        const GrEffectStage* stagePtrs[GrDrawState::kNumStages];
        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
            stagePtrs[s] = &stages[s];
        }
        SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContext(),
                                                              pdesc,
                                                              stagePtrs));
        if (NULL == program.get()) {
            return false;
        }
    }
    return true;
}

static void GLProgramsTest(skiatest::Reporter* reporter, GrContextFactory* factory) {
    for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
        GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
        if (NULL != context) {
            GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
            int maxStages = GrDrawState::kNumStages;
#if SK_ANGLE
            // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
            if (type == GrContextFactory::kANGLE_GLContextType) {
                maxStages = 3;
            }
#endif
            REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
        }
    }
}

#include "TestClassDef.h"
DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)

// This is evil evil evil. The linker may throw away whole translation units as dead code if it
// thinks none of the functions are called. It will do this even if there are static initializers
// in the unit that could pass pointers to functions from the unit out to other translation units!
// We force some of the effects that would otherwise be discarded to link here.

#include "SkLightingImageFilter.h"
#include "SkMagnifierImageFilter.h"
#include "SkColorMatrixFilter.h"

void forceLinking();

void forceLinking() {
    SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
    SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1);
    GrConfigConversionEffect::Create(NULL,
                                     false,
                                     GrConfigConversionEffect::kNone_PMConversion,
                                     SkMatrix::I());
    SkScalar matrix[20];
    SkColorMatrixFilter cmf(matrix);
}

#endif
<|endoftext|>


<commit_before>#include "ScreenJogo.hpp"
#include "Config.hpp"
#include "MusicManager.hpp"
#include "PaoInferior.hpp"
#include "PaoSuperior.hpp"
#include "TextureManager.hpp"
#include "Utils.hpp"

#include <iostream>

#define VELOCIDADE_QUEDA 30
#define VELOCIDADE_HORIZONTAL 7

#define MOVE_STACK_UP_VELOCITY 5
#define MOVE_STACK_RIGHT_VELOCITY 5

void setPosicaoInicial( Food* ingrediente );

ScreenJogo::ScreenJogo( GameRef& gameRef, Fila* fila, Fila* minha )
    : Screen( gameRef ) {
    loadAssets();
    caindo               = false;
    movendoHorizontal    = true;
    velocidadeHorizontal = VELOCIDADE_HORIZONTAL;
    this->filaMinha      = minha;
    this->filaModelo     = fila;

    modeloLanche = nullptr;
    meuLanche    = nullptr;
}

ScreenJogo::~ScreenJogo() {
    delete ingrediente;
}

void ScreenJogo::loadAssets() {
    TextureManager::add( "backgroundJogo", "jogo.jpg" );
    background.setTexture( TextureManager::get( "backgroundJogo" ) );

    TextureManager::add( "barraModelo", "barra_model.png" );
    barModel.setTexture( TextureManager::get( "barraModelo" ) );
    barModel.setPosition( 640, 30 );

    MusicManager::add( "musicJogar", "background.ogg" );
    music = &MusicManager::get( "musicJogar" );

    ingrediente = Utils::sortearQualquerItem();
    ingrediente->setPosition( WINDOW_WIDTH / 2 - ingrediente->getGlobalBounds().width / 2, 0 );
}
void ScreenJogo::draw() {
    window->clear();

    window->draw( background );

    window->draw( *modeloLanche );
    window->draw( *meuLanche );

    if( ingrediente != nullptr ) {
        window->draw( *ingrediente );
    }

    window->display();
}
void ScreenJogo::update() {
    while( window->pollEvent( *event ) ) {
        if( event->type == sf::Event::Closed ) {
            music->stop();
            window->close();
        }

        if( inputManager->keyPressed( sf::Keyboard::Space ) ) {
            movendoHorizontal = false;
            caindo            = true;
        }
    }

    if( *isAudioOn && music->getStatus() != sf::SoundSource::Status::Playing ) {
        music->play();
    }

    if( modeloLanche == nullptr ) {
        modeloLanche = filaModelo->Retira();
        modeloLanche->setPosition( 0, WINDOW_HEIGHT - 85 );
    }

    if( meuLanche == nullptr ) {
        meuLanche = new Lanche( modeloLanche->getTamanho() );
        meuLanche->inserir( new PaoInferior() );
        meuLanche->setPosition( WINDOW_WIDTH / 2 - 50, WINDOW_HEIGHT - 85 );
    }

    movimentar();

    if( caindo ) {
        if( Collision::PixelPerfectTest( *ingrediente, *meuLanche->getTopo() ) ) {
            caindo = false;
            if( !ingrediente->getComidaCerta() ) {
                delete ingrediente;
                ingrediente = nullptr;
                music->stop();
                *nextScreen = PERDEU;
            } else {
                ingrediente->setPosition( meuLanche->getTopo()->getPosition().x,
                                          meuLanche->getTopo()->getPosition().y -
                                              INGREDIENTE_MARGIN );
                meuLanche->inserir( ingrediente );
            }
        } else if( meuLanche->faltaApenasPaoSuperior() &&
                   ingrediente->getAlias() == "paoSuperior" &&
                   Utils::isForaDaJanelaVerticalmente( ingrediente ) ) {
            caindo = false;
            delete ingrediente;
            ingrediente = nullptr;
            music->stop();
            *nextScreen = PERDEU;
        }
    }

    draw();

    if( meuLanche->getTamanho() == modeloLanche->getTamanho() ) {
        filaMinha->Insere( meuLanche );
        if( !filaModelo->Vazia() ) {
            modeloLanche = nullptr;
            meuLanche    = nullptr;
        } else {
            ingrediente = nullptr;
            music->stop();
            *nextScreen = COMPARA;
        }
    }
}

void ScreenJogo::movimentar() {
    if( movendoHorizontal ) {
        if( Utils::isForaDaJanelaHorizontalmente( ingrediente ) ) {
            velocidadeHorizontal = -1 * velocidadeHorizontal;
        }
        ingrediente->move( velocidadeHorizontal, 0 );

    } else if( caindo ) {
        if( Utils::isForaDaJanelaVerticalmente( ingrediente ) ) {
            caindo = false;
        } else {
            ingrediente->move( 0, VELOCIDADE_QUEDA );
        }
    } else {
        if( meuLanche->faltaApenasPaoSuperior() ) {
            ingrediente = new PaoSuperior();
        } else {
            ingrediente = Utils::sortearQualquerItem();
        }
        setPosicaoInicial( ingrediente );
        movendoHorizontal = true;
    }
}

void setPosicaoInicial( Food* ingrediente ) {
    ingrediente->setPosition( WINDOW_WIDTH / 2 - ingrediente->getGlobalBounds().width / 2, 0 );
}
<commit_msg>Aumentando velocidade horizontal<commit_after>#include "ScreenJogo.hpp"
#include "Config.hpp"
#include "MusicManager.hpp"
#include "PaoInferior.hpp"
#include "PaoSuperior.hpp"
#include "TextureManager.hpp"
#include "Utils.hpp"

#include <iostream>

#define VELOCIDADE_QUEDA 30
#define VELOCIDADE_HORIZONTAL 7

#define MOVE_STACK_UP_VELOCITY 5
#define MOVE_STACK_RIGHT_VELOCITY 5

void setPosicaoInicial( Food* ingrediente );

ScreenJogo::ScreenJogo( GameRef& gameRef, Fila* fila, Fila* minha )
    : Screen( gameRef ) {
    loadAssets();
    caindo               = false;
    movendoHorizontal    = true;
    velocidadeHorizontal = VELOCIDADE_HORIZONTAL;
    this->filaMinha      = minha;
    this->filaModelo     = fila;

    modeloLanche = nullptr;
    meuLanche    = nullptr;
}

ScreenJogo::~ScreenJogo() {
    delete ingrediente;
}

void ScreenJogo::loadAssets() {
    TextureManager::add( "backgroundJogo", "jogo.jpg" );
    background.setTexture( TextureManager::get( "backgroundJogo" ) );

    TextureManager::add( "barraModelo", "barra_model.png" );
    barModel.setTexture( TextureManager::get( "barraModelo" ) );
    barModel.setPosition( 640, 30 );

    MusicManager::add( "musicJogar", "background.ogg" );
    music = &MusicManager::get( "musicJogar" );

    ingrediente = Utils::sortearQualquerItem();
    ingrediente->setPosition( WINDOW_WIDTH / 2 - ingrediente->getGlobalBounds().width / 2, 0 );
}
void ScreenJogo::draw() {
    window->clear();

    window->draw( background );

    window->draw( *modeloLanche );
    window->draw( *meuLanche );

    if( ingrediente != nullptr ) {
        window->draw( *ingrediente );
    }

    window->display();
}
void ScreenJogo::update() {
    while( window->pollEvent( *event ) ) {
        if( event->type == sf::Event::Closed ) {
            music->stop();
            window->close();
        }

        if( inputManager->keyPressed( sf::Keyboard::Space ) ) {
            movendoHorizontal = false;
            caindo            = true;
        }
    }

    if( *isAudioOn && music->getStatus() != sf::SoundSource::Status::Playing ) {
        music->play();
    }

    if( modeloLanche == nullptr ) {
        modeloLanche = filaModelo->Retira();
        modeloLanche->setPosition( 0, WINDOW_HEIGHT - 85 );
    }

    if( meuLanche == nullptr ) {
        meuLanche = new Lanche( modeloLanche->getTamanho() );
        meuLanche->inserir( new PaoInferior() );
        meuLanche->setPosition( WINDOW_WIDTH / 2 - 50, WINDOW_HEIGHT - 85 );
    }

    movimentar();

    if( caindo ) {
        if( Collision::PixelPerfectTest( *ingrediente, *meuLanche->getTopo() ) ) {
            caindo = false;
            if( !ingrediente->getComidaCerta() ) {
                delete ingrediente;
                ingrediente = nullptr;
                music->stop();
                *nextScreen = PERDEU;
            } else {
                ingrediente->setPosition( meuLanche->getTopo()->getPosition().x,
                                          meuLanche->getTopo()->getPosition().y -
                                              INGREDIENTE_MARGIN );
                meuLanche->inserir( ingrediente );
            }
        } else if( meuLanche->faltaApenasPaoSuperior() &&
                   ingrediente->getAlias() == "paoSuperior" &&
                   Utils::isForaDaJanelaVerticalmente( ingrediente ) ) {
            caindo = false;
            delete ingrediente;
            ingrediente = nullptr;
            music->stop();
            *nextScreen = PERDEU;
        }
    }

    draw();

    if( meuLanche->getTamanho() == modeloLanche->getTamanho() ) {
        if( velocidadeHorizontal > 0 ) {
            velocidadeHorizontal += 1;
        } else {
            velocidadeHorizontal -= 1;
        }

        filaMinha->Insere( meuLanche );
        if( !filaModelo->Vazia() ) {
            modeloLanche = nullptr;
            meuLanche    = nullptr;
        } else {
            ingrediente = nullptr;
            music->stop();
            *nextScreen = COMPARA;
        }
    }
}

void ScreenJogo::movimentar() {
    if( movendoHorizontal ) {
        if( Utils::isForaDaJanelaHorizontalmente( ingrediente ) ) {
            velocidadeHorizontal = -1 * velocidadeHorizontal;
        }
        ingrediente->move( velocidadeHorizontal, 0 );

    } else if( caindo ) {
        if( Utils::isForaDaJanelaVerticalmente( ingrediente ) ) {
            caindo = false;
        } else {
            ingrediente->move( 0, VELOCIDADE_QUEDA );
        }
    } else {
        if( meuLanche->faltaApenasPaoSuperior() ) {
            ingrediente = new PaoSuperior();
        } else {
            ingrediente = Utils::sortearQualquerItem();
        }
        setPosicaoInicial( ingrediente );
        movendoHorizontal = true;
    }
}

void setPosicaoInicial( Food* ingrediente ) {
    ingrediente->setPosition( WINDOW_WIDTH / 2 - ingrediente->getGlobalBounds().width / 2, 0 );
}
<|endoftext|>


<commit_before>#include "ocilib_tests.h"

TEST(ReportedIssues, Issue216)
{
    ASSERT_TRUE(OCI_Initialize(nullptr, HOME, OCI_ENV_DEFAULT));

    const auto conn = OCI_ConnectionCreate(DBS, USR, PWD, OCI_SESSION_DEFAULT);
    ASSERT_NE(nullptr, conn);

    ASSERT_TRUE(OCI_Immediate(conn, OTEXT("CREATE TABLE ISSUE_216(ID NUMBER, DATEVALUE DATE)")));

    const auto stmt = OCI_StatementCreate(conn);
    ASSERT_NE(nullptr, stmt);

    const int totalRowCount = 54;
    const int bufferSize = 50;

    int offset = 0;
    int actualRowCount = bufferSize;

    auto ints = static_cast<int*>(calloc(actualRowCount, sizeof(int)));
    auto dates = static_cast<OCI_Date**>(calloc(actualRowCount, sizeof(OCI_Date*)));

    ASSERT_TRUE(OCI_Prepare(stmt, OTEXT("INSERT INTO ISSUE_216(ID, DATEVALUE) VALUES(:i, :d)")));
    ASSERT_TRUE(OCI_BindArraySetSize(stmt, bufferSize));
    ASSERT_TRUE(OCI_BindArrayOfInts(stmt, OTEXT(":i"), ints, 0));
    ASSERT_TRUE(OCI_BindArrayOfDates(stmt, OTEXT(":d"), dates, 0));

    while (offset < totalRowCount)
    {
        for (int i = 0; i < actualRowCount; i++)
        {
            if (dates[i])
            {
                ASSERT_TRUE(OCI_DateFree(dates[i]));
            }
        }

        actualRowCount = totalRowCount - offset < bufferSize ? totalRowCount - offset : bufferSize;

        for (int i = 0; i < actualRowCount; i++)
        {
            ints[i] = i;
            dates[i] = OCI_DateCreate(NULL);
            ASSERT_NE(nullptr, dates[i]);
            ASSERT_TRUE(OCI_DateSysDate(dates[i]));
        }

        if (actualRowCount < bufferSize)
        {
            ASSERT_TRUE(OCI_BindArraySetSize(stmt, actualRowCount));
        }

        ASSERT_TRUE(OCI_Execute(stmt));
        offset += actualRowCount;
    }

    ASSERT_EQ(totalRowCount, offset);

    for (int i = 0; i < actualRowCount; i++)
    {
        ASSERT_TRUE(OCI_DateFree(dates[i]));
    }

    ASSERT_TRUE(OCI_Immediate(conn, OTEXT("DROP TABLE ISSUE_216")));

    ASSERT_TRUE(OCI_ConnectionFree(conn));
    ASSERT_TRUE(OCI_Cleanup());
}

TEST(ReportedIssues, Issue225)
{
    ASSERT_TRUE(OCI_Initialize(nullptr, HOME, OCI_ENV_DEFAULT));

    const auto conn = OCI_ConnectionCreate(DBS, USR, PWD, OCI_SESSION_DEFAULT);
    ASSERT_NE(nullptr, conn);

    ASSERT_TRUE(OCI_ServerEnableOutput(conn, 32000, 5, 255));

    const auto stmt = OCI_StatementCreate(conn);
    ASSERT_NE(nullptr, stmt);

    ASSERT_TRUE(OCI_Prepare(stmt,
        OTEXT(
            "declare "
            "type val_tab is table of number index by binary_integer;"
            "procedure Test( v IN OUT val_tab ) is "
            "begin "
            "DBMS_OUTPUT.PUT_LINE(v.count); "
            "for i in 1..v.count loop "
            "  v(i) := i+10; "
            "  DBMS_OUTPUT.PUT_LINE('v('||i||') = '||v(i));"
            "end loop; "
            "end Test; "
            "begin "
            " Test(:v);"
            " end;")));

    std::array<OCI_Number*, 3> numbers;

    for (size_t i = 0; i < numbers.size(); i++)
    {
        numbers[i] = OCI_NumberCreate(conn);
        ASSERT_NE(nullptr, numbers[i]);
        ASSERT_TRUE(OCI_NumberFromText(numbers[i], TO_STRING(i+1).data(), nullptr));
    }

    ASSERT_TRUE(OCI_BindArrayOfNumbers(stmt, ":v", numbers.data(), static_cast<unsigned int>(numbers.size())));
    ASSERT_TRUE(OCI_BindSetDirection(OCI_GetBind(stmt, 1), OCI_BDM_IN_OUT));
    ASSERT_TRUE(OCI_Execute(stmt));

    ASSERT_EQ(TO_STRING(numbers.size()), ostring(OCI_ServerGetOutput(conn)));

    for (size_t i = 0; i < numbers.size(); i++)
    {
        otext buffer[100];
        osprintf(buffer, 100, OTEXT("v(%d) = %d"), i + 1, i + 1 + 10);
        ASSERT_EQ(ostring(buffer), ostring(OCI_ServerGetOutput(conn)));
    }

    for (size_t i = 0; i < numbers.size(); i++)
    {
        ostring expected = TO_STRING(i+1+10);
        otext buffer[100];
        ASSERT_NE(0, OCI_NumberToText(numbers[i], NULL, 100, buffer));
        ASSERT_EQ(expected, ostring(buffer));
    }

    ASSERT_TRUE(OCI_ConnectionFree(conn));
    ASSERT_TRUE(OCI_Cleanup());
}<commit_msg>Added non regression test for issue #222<commit_after>#include "ocilib_tests.h"

TEST(ReportedIssues, Issue216)
{
    ASSERT_TRUE(OCI_Initialize(nullptr, HOME, OCI_ENV_DEFAULT));

    const auto conn = OCI_ConnectionCreate(DBS, USR, PWD, OCI_SESSION_DEFAULT);
    ASSERT_NE(nullptr, conn);

    ASSERT_TRUE(OCI_Immediate(conn, OTEXT("CREATE TABLE ISSUE_216(ID NUMBER, DATEVALUE DATE)")));

    const auto stmt = OCI_StatementCreate(conn);
    ASSERT_NE(nullptr, stmt);

    const int totalRowCount = 54;
    const int bufferSize = 50;

    int offset = 0;
    int actualRowCount = bufferSize;

    auto ints = static_cast<int*>(calloc(actualRowCount, sizeof(int)));
    auto dates = static_cast<OCI_Date**>(calloc(actualRowCount, sizeof(OCI_Date*)));

    ASSERT_TRUE(OCI_Prepare(stmt, OTEXT("INSERT INTO ISSUE_216(ID, DATEVALUE) VALUES(:i, :d)")));
    ASSERT_TRUE(OCI_BindArraySetSize(stmt, bufferSize));
    ASSERT_TRUE(OCI_BindArrayOfInts(stmt, OTEXT(":i"), ints, 0));
    ASSERT_TRUE(OCI_BindArrayOfDates(stmt, OTEXT(":d"), dates, 0));

    while (offset < totalRowCount)
    {
        for (int i = 0; i < actualRowCount; i++)
        {
            if (dates[i])
            {
                ASSERT_TRUE(OCI_DateFree(dates[i]));
            }
        }

        actualRowCount = totalRowCount - offset < bufferSize ? totalRowCount - offset : bufferSize;

        for (int i = 0; i < actualRowCount; i++)
        {
            ints[i] = i;
            dates[i] = OCI_DateCreate(NULL);
            ASSERT_NE(nullptr, dates[i]);
            ASSERT_TRUE(OCI_DateSysDate(dates[i]));
        }

        if (actualRowCount < bufferSize)
        {
            ASSERT_TRUE(OCI_BindArraySetSize(stmt, actualRowCount));
        }

        ASSERT_TRUE(OCI_Execute(stmt));
        offset += actualRowCount;
    }

    ASSERT_EQ(totalRowCount, offset);

    for (int i = 0; i < actualRowCount; i++)
    {
        ASSERT_TRUE(OCI_DateFree(dates[i]));
    }

    ASSERT_TRUE(OCI_Immediate(conn, OTEXT("DROP TABLE ISSUE_216")));

    ASSERT_TRUE(OCI_ConnectionFree(conn));
    ASSERT_TRUE(OCI_Cleanup());
}

TEST(ReportedIssues, Issue222)
{
    ASSERT_TRUE(OCI_Initialize(nullptr, HOME, OCI_ENV_DEFAULT));

    const auto pool = OCI_PoolCreate(DBS, USR, PWD, OCI_POOL_SESSION, OCI_SESSION_SYSDBA, 0, 1, 1);
    ASSERT_NE(nullptr, pool);

    const auto conn = OCI_PoolGetConnection(pool, nullptr);
    ASSERT_NE(nullptr, conn);

    ASSERT_TRUE(OCI_ConnectionFree(conn));
    ASSERT_TRUE(OCI_PoolFree(pool));
    ASSERT_TRUE(OCI_Cleanup());
}

TEST(ReportedIssues, Issue225)
{
    ASSERT_TRUE(OCI_Initialize(nullptr, HOME, OCI_ENV_DEFAULT));

    const auto conn = OCI_ConnectionCreate(DBS, USR, PWD, OCI_SESSION_DEFAULT);
    ASSERT_NE(nullptr, conn);

    ASSERT_TRUE(OCI_ServerEnableOutput(conn, 32000, 5, 255));

    const auto stmt = OCI_StatementCreate(conn);
    ASSERT_NE(nullptr, stmt);

    ASSERT_TRUE(OCI_Prepare(stmt,
        OTEXT(
            "declare "
            "type val_tab is table of number index by binary_integer;"
            "procedure Test( v IN OUT val_tab ) is "
            "begin "
            "DBMS_OUTPUT.PUT_LINE(v.count); "
            "for i in 1..v.count loop "
            "  v(i) := i+10; "
            "  DBMS_OUTPUT.PUT_LINE('v('||i||') = '||v(i));"
            "end loop; "
            "end Test; "
            "begin "
            " Test(:v);"
            " end;")));

    std::array<OCI_Number*, 3> numbers;

    for (size_t i = 0; i < numbers.size(); i++)
    {
        numbers[i] = OCI_NumberCreate(conn);
        ASSERT_NE(nullptr, numbers[i]);
        ASSERT_TRUE(OCI_NumberFromText(numbers[i], TO_STRING(i+1).data(), nullptr));
    }

    ASSERT_TRUE(OCI_BindArrayOfNumbers(stmt, ":v", numbers.data(), static_cast<unsigned int>(numbers.size())));
    ASSERT_TRUE(OCI_BindSetDirection(OCI_GetBind(stmt, 1), OCI_BDM_IN_OUT));
    ASSERT_TRUE(OCI_Execute(stmt));

    ASSERT_EQ(TO_STRING(numbers.size()), ostring(OCI_ServerGetOutput(conn)));

    for (size_t i = 0; i < numbers.size(); i++)
    {
        otext buffer[100];
        osprintf(buffer, 100, OTEXT("v(%d) = %d"), i + 1, i + 1 + 10);
        ASSERT_EQ(ostring(buffer), ostring(OCI_ServerGetOutput(conn)));
    }

    for (size_t i = 0; i < numbers.size(); i++)
    {
        ostring expected = TO_STRING(i+1+10);
        otext buffer[100];
        ASSERT_NE(0, OCI_NumberToText(numbers[i], NULL, 100, buffer));
        ASSERT_EQ(expected, ostring(buffer));
    }

    ASSERT_TRUE(OCI_ConnectionFree(conn));
    ASSERT_TRUE(OCI_Cleanup());
}<|endoftext|>


<commit_before>#include "oddbot_boot/oddbot_boot_module.h"

oddbot_boot_module::oddbot_boot_module(){
	//subscribe to oddbot_boot
	//publish to oddbot_boot_stop
  ros::NodeHandle nodeHandle;
  boot_pub = nodeHandle.advertise<oddbot_msgs::OddbotBoot>("boot", 1000);
  stop_sub = nodeHandle.subscribe("boot_stop", 1000, &oddbot_boot_module::get_info, this);
  subnet = get_subnet();
}
// Callback message
void oddbot_boot_module::get_info(const oddbot_msgs::OddbotBootStop::ConstPtr& stop_msg){

	//check my IP address
	if (stop_msg->subnet == subnet) {
    //set stop running flag
    subnet_msg_stop = true;
  }
}

void oddbot_boot_module::send_info(){
  // Set the subnet
  module_info_msg.subnet = subnet;
	// Publish the subnet
  boot_pub.publish(module_info_msg);
}

bool oddbot_boot_module::get_subnet_msg_stop() {
  return subnet_msg_stop;
}

int oddbot_boot_module::get_subnet(){
  int fd;
  struct ifreq ifr;

  fd = socket(AF_INET, SOCK_DGRAM, 0);

  /* I want to get an IPv4 IP address */
  ifr.ifr_addr.sa_family = AF_INET;

  /* I want IP address attached to "subnet" */
  strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);

  ioctl(fd, SIOCGIFADDR, &ifr);

  close(fd);

  char *address = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
  std::stringstream s(address);
  int a, b, c, d;
  char ch;
  s >> a >> ch >> b >> ch >> c >> ch >> d;
  return c;
}

int main(int argc, char** argv){

	//stop when stop running flag is true
	ros::init(argc, argv, "oddbot_boot_module");

  oddbot_boot_module module = oddbot_boot_module();

  ROS_INFO("oddbot boot module node started!");

  ros::Rate loop_rate(10);

  while (ros::ok() && !module.get_subnet_msg_stop())
  {
    module.send_info();
    ros::spinOnce();
    loop_rate.sleep();
  }
  ROS_INFO("you gon die now");
  return 0;
}
<commit_msg>removing old files<commit_after><|endoftext|>


<commit_before>#include "http/http.hpp"
#include <iostream>
#include <boost/bind.hpp>
#include "logger.hpp"

std::string http_req_t::find_query_param(std::string key) const {
    //TODO this is inefficient we should actually load it all into a map
    for (std::vector<query_parameter_t>::const_iterator it = query_params.begin(); it != query_params.end(); it++) {
        if (it->key == key) return it->val;
    }
    return std::string("");
}

std::string http_req_t::find_header_line(std::string key) const {
    //TODO this is inefficient we should actually load it all into a map
    for (std::vector<header_line_t>::const_iterator it = header_lines.begin(); it != header_lines.end(); it++) {
        if (it->key == key) return it->val;
    }
    return std::string("");
}

int content_length(http_req_t msg) {
    for (std::vector<header_line_t>::iterator it = msg.header_lines.begin(); it != msg.header_lines.end(); it++) {
        if (it->key == std::string("Content-Length"))
            return atoi(it->val.c_str());
    }
    return 0;
}

void http_res_t::add_header_line(std::string const &key, std::string const &val) {
    header_line_t hdr_ln;
    hdr_ln.key = key;
    hdr_ln.val = val;
    header_lines.push_back(hdr_ln);
}

void http_res_t::set_body(std::string const &content_type, std::string const &content) {
    for (std::vector<header_line_t>::iterator it = header_lines.begin(); it != header_lines.end(); it++) {
        rassert(it->key != "Content-Type");
        rassert(it->key != "Conent-Length");
    }
    rassert(body.size() == 0);

    add_header_line("Content-Type", content_type);

    std::ostringstream res;
    res << content.size();
    add_header_line("Content-Length", res.str());

    body = content;
}

typedef std::string::const_iterator str_iterator_type;
typedef http_msg_parser_t<str_iterator_type> str_http_msg_parser_t;

typedef tcp_conn_t::iterator tcp_iterator_type;
typedef http_msg_parser_t<tcp_iterator_type> tcp_http_msg_parser_t;

void test_header_parser() {
    http_req_t res;
    str_http_msg_parser_t http_msg_parser;
    std::string header =
        "GET /foo/bar HTTP/1.1\r\n"
        "Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n"
        "Content-Type: text/html\r\n"
        "Content-Length: 0\r\n"
        "\r\n"
        ;
    std::string::const_iterator iter = header.begin();
    std::string::const_iterator end = header.end();
    bool success = parse(iter, end, http_msg_parser, res);
    BREAKPOINT;
    success = true;
}

http_server_t::http_server_t(int port) {
    tcp_listener.reset(new tcp_listener_t(port, boost::bind(&http_server_t::handle_conn, this, _1)));
}

std::string human_readable_status(int code) {
    switch(code) {
    case 200:
        return "OK";
    case 204:
        return "No Content";
    case 400:
        return "Bad Request";
    case 404:
        return "Not Found";
    default:
        unreachable();
    }
}

void write_http_msg(boost::scoped_ptr<tcp_conn_t> &conn, http_res_t const &res) {
    conn->writef("HTTP/%s %d %s\r\n", res.version.c_str(), res.code, human_readable_status(res.code).c_str());
    for (std::vector<header_line_t>::const_iterator it = res.header_lines.begin(); it != res.header_lines.end(); it++) {
        conn->writef("%s: %s\r\n", it->key.c_str(), it->val.c_str());
    }
    conn->writef("\r\n");
    conn->writef("%s", res.body.c_str());
}

void http_server_t::handle_conn(boost::scoped_ptr<tcp_conn_t> &conn) {
    //BREAKPOINT;
    http_req_t req;
    tcp_http_msg_parser_t http_msg_parser;

    //debug(http_msg_parser);

    tcp_iterator_type iter = conn->begin();
    tcp_iterator_type end = conn->end();

    /* parse the request */
    if (parse(iter, end, http_msg_parser, req)) {
        conn->pop(iter);
        const_charslice slc = conn->peek(4);

        if (strncmp(slc.beg, "\r\n\r\n", 4) != 0) {
            goto PARSE_ERROR;
        }
        conn->pop(4);

        slc = conn->peek(content_length(req));
        req.body.append(slc.beg, content_length(req));
        conn->pop(content_length(req));

        logINF("Request for: %s\n", req.resource.c_str());

        http_res_t res = handle(req);
        res.version = req.version;
        write_http_msg(conn, res);
    }

    return;

PARSE_ERROR:
    http_res_t res;
    res.code = 400;
    write_http_msg(conn, res);
}

test_server_t::test_server_t(int port)
    : http_server_t(port)
{ }

http_res_t test_server_t::handle(const http_req_t &req) {
    http_res_t res;

    res.version = req.version;
    res.code = 200;

    res.add_header_line("Vary", "Accept-Encoding");
    res.add_header_line("Content-Length", "0");

    return res;
}
<commit_msg>Change logINF to logDBG.<commit_after>#include "http/http.hpp"
#include <iostream>
#include <boost/bind.hpp>
#include "logger.hpp"

std::string http_req_t::find_query_param(std::string key) const {
    //TODO this is inefficient we should actually load it all into a map
    for (std::vector<query_parameter_t>::const_iterator it = query_params.begin(); it != query_params.end(); it++) {
        if (it->key == key) return it->val;
    }
    return std::string("");
}

std::string http_req_t::find_header_line(std::string key) const {
    //TODO this is inefficient we should actually load it all into a map
    for (std::vector<header_line_t>::const_iterator it = header_lines.begin(); it != header_lines.end(); it++) {
        if (it->key == key) return it->val;
    }
    return std::string("");
}

int content_length(http_req_t msg) {
    for (std::vector<header_line_t>::iterator it = msg.header_lines.begin(); it != msg.header_lines.end(); it++) {
        if (it->key == std::string("Content-Length"))
            return atoi(it->val.c_str());
    }
    return 0;
}

void http_res_t::add_header_line(std::string const &key, std::string const &val) {
    header_line_t hdr_ln;
    hdr_ln.key = key;
    hdr_ln.val = val;
    header_lines.push_back(hdr_ln);
}

void http_res_t::set_body(std::string const &content_type, std::string const &content) {
    for (std::vector<header_line_t>::iterator it = header_lines.begin(); it != header_lines.end(); it++) {
        rassert(it->key != "Content-Type");
        rassert(it->key != "Conent-Length");
    }
    rassert(body.size() == 0);

    add_header_line("Content-Type", content_type);

    std::ostringstream res;
    res << content.size();
    add_header_line("Content-Length", res.str());

    body = content;
}

typedef std::string::const_iterator str_iterator_type;
typedef http_msg_parser_t<str_iterator_type> str_http_msg_parser_t;

typedef tcp_conn_t::iterator tcp_iterator_type;
typedef http_msg_parser_t<tcp_iterator_type> tcp_http_msg_parser_t;

void test_header_parser() {
    http_req_t res;
    str_http_msg_parser_t http_msg_parser;
    std::string header =
        "GET /foo/bar HTTP/1.1\r\n"
        "Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n"
        "Content-Type: text/html\r\n"
        "Content-Length: 0\r\n"
        "\r\n"
        ;
    std::string::const_iterator iter = header.begin();
    std::string::const_iterator end = header.end();
    bool success = parse(iter, end, http_msg_parser, res);
    BREAKPOINT;
    success = true;
}

http_server_t::http_server_t(int port) {
    tcp_listener.reset(new tcp_listener_t(port, boost::bind(&http_server_t::handle_conn, this, _1)));
}

std::string human_readable_status(int code) {
    switch(code) {
    case 200:
        return "OK";
    case 204:
        return "No Content";
    case 400:
        return "Bad Request";
    case 404:
        return "Not Found";
    default:
        unreachable();
    }
}

void write_http_msg(boost::scoped_ptr<tcp_conn_t> &conn, http_res_t const &res) {
    conn->writef("HTTP/%s %d %s\r\n", res.version.c_str(), res.code, human_readable_status(res.code).c_str());
    for (std::vector<header_line_t>::const_iterator it = res.header_lines.begin(); it != res.header_lines.end(); it++) {
        conn->writef("%s: %s\r\n", it->key.c_str(), it->val.c_str());
    }
    conn->writef("\r\n");
    conn->writef("%s", res.body.c_str());
}

void http_server_t::handle_conn(boost::scoped_ptr<tcp_conn_t> &conn) {
    //BREAKPOINT;
    http_req_t req;
    tcp_http_msg_parser_t http_msg_parser;

    //debug(http_msg_parser);

    tcp_iterator_type iter = conn->begin();
    tcp_iterator_type end = conn->end();

    /* parse the request */
    if (parse(iter, end, http_msg_parser, req)) {
        conn->pop(iter);
        const_charslice slc = conn->peek(4);

        if (strncmp(slc.beg, "\r\n\r\n", 4) != 0) {
            goto PARSE_ERROR;
        }
        conn->pop(4);

        slc = conn->peek(content_length(req));
        req.body.append(slc.beg, content_length(req));
        conn->pop(content_length(req));

        logDBG("Request for: %s\n", req.resource.c_str());

        http_res_t res = handle(req);
        res.version = req.version;
        write_http_msg(conn, res);
    }

    return;

PARSE_ERROR:
    http_res_t res;
    res.code = 400;
    write_http_msg(conn, res);
}

test_server_t::test_server_t(int port)
    : http_server_t(port)
{ }

http_res_t test_server_t::handle(const http_req_t &req) {
    http_res_t res;

    res.version = req.version;
    res.code = 200;

    res.add_header_line("Vary", "Accept-Encoding");
    res.add_header_line("Content-Length", "0");

    return res;
}
<|endoftext|>


<commit_before>// 01.01.2017 Султан Xottab_DUTY Урамаев
// Чем стрелы коленом ловить, гораздо интереснее отстреливать свои ноги. Продолжим.
#include <GLFW/glfw3.h>
#include <fmt/format.h>

#include "xdEngine.hpp"
#include "xdCore.hpp"
#include "Console.hpp"
#include "ConsoleCommand.hpp"

XDAY_API XDayEngine Engine;

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        ConsoleCommands->Execute(&ExitCC);
    if (key == GLFW_KEY_ENTER && action == GLFW_PRESS)
        ConsoleCommands->Execute(fmt::format("r_fullscreen {}", !ConsoleCommands->GetBool("r_fullscreen")));
}

void XDayEngine::Initialize()
{
    monitors = glfwGetMonitors(&MonitorsCount);
    CurrentMonitor = glfwGetPrimaryMonitor();

    VideoModes = glfwGetVideoModes(CurrentMonitor, &VideoModesCount);
    CurrentMode = glfwGetVideoMode(CurrentMonitor);

    glfwWindowHint(GLFW_RED_BITS, CurrentMode->redBits);
    glfwWindowHint(GLFW_GREEN_BITS, CurrentMode->greenBits);
    glfwWindowHint(GLFW_BLUE_BITS, CurrentMode->blueBits);
    glfwWindowHint(GLFW_REFRESH_RATE, CurrentMode->refreshRate);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}

void XDayEngine::xdCreateWindow()
{
    if (ConsoleCommands->GetBool("r_fullscreen"))
        window = glfwCreateWindow(CurrentMode->width, CurrentMode->height, Core.AppName.c_str(), CurrentMonitor, nullptr);
    else
        window = glfwCreateWindow(CurrentMode->width-256, CurrentMode->height-256, Core.AppName.c_str(), nullptr, nullptr);
    glfwSetKeyCallback(window, key_callback);
}
<commit_msg>Directly ExecuteBool() instead of Execute()<commit_after>// 01.01.2017 Султан Xottab_DUTY Урамаев
// Чем стрелы коленом ловить, гораздо интереснее отстреливать свои ноги. Продолжим.
#include <GLFW/glfw3.h>

#include "xdEngine.hpp"
#include "xdCore.hpp"
#include "ConsoleCommand.hpp"

XDAY_API XDayEngine Engine;

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        ConsoleCommands->Execute(&ExitCC);
    if (key == GLFW_KEY_ENTER && action == GLFW_PRESS)
        ConsoleCommands->ExecuteBool(&FullscreenCC, !ConsoleCommands->GetBool(&FullscreenCC));
}

void XDayEngine::Initialize()
{
    monitors = glfwGetMonitors(&MonitorsCount);
    CurrentMonitor = glfwGetPrimaryMonitor();

    VideoModes = glfwGetVideoModes(CurrentMonitor, &VideoModesCount);
    CurrentMode = glfwGetVideoMode(CurrentMonitor);

    glfwWindowHint(GLFW_RED_BITS, CurrentMode->redBits);
    glfwWindowHint(GLFW_GREEN_BITS, CurrentMode->greenBits);
    glfwWindowHint(GLFW_BLUE_BITS, CurrentMode->blueBits);
    glfwWindowHint(GLFW_REFRESH_RATE, CurrentMode->refreshRate);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}

void XDayEngine::xdCreateWindow()
{
    if (ConsoleCommands->GetBool("r_fullscreen"))
        window = glfwCreateWindow(CurrentMode->width, CurrentMode->height, Core.AppName.c_str(), CurrentMonitor, nullptr);
    else
        window = glfwCreateWindow(CurrentMode->width-256, CurrentMode->height-256, Core.AppName.c_str(), nullptr, nullptr);
    glfwSetKeyCallback(window, key_callback);
}
<|endoftext|>


<commit_before>//  Copyright 2011 Gregory Szorc
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#ifndef ZIPPYLOG_HPP_
#define ZIPPYLOG_HPP_

// windows requires a special macro to export symbols from libraries
// we use the token ZIPPYLOG_IMPORT for this
// if we are on Windows, we export symbols by default.
// If ZIPPYLOG_IMPORT is defined, we tell the compiler we're looking for
// external symbols.
// Else, we're not on Windows and the keyword does nothing.
// @todo utilize GCC's visibility attribute (http://gcc.gnu.org/wiki/Visibility)
#ifdef WINDOWS
#if defined(ZIPPYLOG_IMPORT)
#define ZIPPYLOG_EXPORT __declspec(dllimport)
#else
#define ZIPPYLOG_EXPORT __declspec(dllexport)
#endif
#else
#define ZIPPYLOG_EXPORT
#endif

/* define 32 and 64 bit integer types */
// @todo these should be namespaced
#ifdef WINDOWS
typedef __int32 int32;
typedef __int64 int64;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
#elif HAVE_STDINT
#include <stdint.h>
typedef int32_t int32;
typedef int64_t int64;
typedef uint32_t uint32;
typedef uint64_t uint64;
#else
#error "Integer types not defined on this platform"
#endif

#include <stdexcept>
#include <string>

namespace zippylog {

/// The base zippylog exception
///
/// Zippylog code is expected to throw an exception derived from this for all
/// run-time errors. Zippylog code is allowed to throw exceptions derived from
/// std::logic_error if it makes sense (e.g. obvious coding error)
class ZIPPYLOG_EXPORT Exception : public ::std::runtime_error
{
    public:
        Exception(::std::string const &msg) : ::std::runtime_error(msg) { }
};

/// An error when deserializing a message
class ZIPPYLOG_EXPORT DeserializeException : public ::std::runtime_error
{
    public:
        DeserializeException() : runtime_error("could not deserialize message") { }
};

// initializes the zippylog system
// this should be called at the beginning of every program/library that uses zippylog
ZIPPYLOG_EXPORT void initialize_library();

// runs zippylog shutdown procedures
// This should be executed before process exit or when zippylog is no longer
// needed by a process.
//
// It isn't required to call this function. However, not doing so will result
// in leaked memory.
ZIPPYLOG_EXPORT void shutdown_library();

static const uint32 message_namespace = 1;

/// Default number of persisted state reactor threads for the server device
static const uint32 server_default_persisted_state_reactor_threads = 1;

/// Default number of worker threads for the server device
static const uint32 server_default_worker_threads = 2;

/// Default subscription TTL for server device (in milliseconds)
static const uint32 server_default_subscription_ttl = 60000;

/// Default stream flush interval for server device (in milliseconds)
static const uint32 server_default_stream_flush_interval = 5000;

/// Default bucket to log internal events to in server device
static const ::std::string server_default_log_bucket = "zippylog";

/// Default stream set to log internal events to in server device
static const ::std::string server_default_log_stream_set = "server";

/// Default value for whether to allow remote-supplied Lua code in server device
static const uint32 server_default_lua_allow = false;

/// Default maximum Lua allocation limit for streaming states, in bytes
static const uint32 server_default_lua_streaming_max_memory = 524288;

static const uint32 lua_default_subscription_memory_ceiling = 524288;

static const uint32 lua_default_plugin_memory_ceiling = 524288;

} // namespace

#endif
<commit_msg>documentation<commit_after>//  Copyright 2011 Gregory Szorc
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#ifndef ZIPPYLOG_HPP_
#define ZIPPYLOG_HPP_

// windows requires a special macro to export symbols from libraries
// we use the token ZIPPYLOG_IMPORT for this
// if we are on Windows, we export symbols by default.
// If ZIPPYLOG_IMPORT is defined, we tell the compiler we're looking for
// external symbols.
// Else, we're not on Windows and the keyword does nothing.
// @todo utilize GCC's visibility attribute (http://gcc.gnu.org/wiki/Visibility)
#ifdef WINDOWS
#if defined(ZIPPYLOG_IMPORT)
#define ZIPPYLOG_EXPORT __declspec(dllimport)
#else
#define ZIPPYLOG_EXPORT __declspec(dllexport)
#endif
#else
#define ZIPPYLOG_EXPORT
#endif

/* define 32 and 64 bit integer types */
// @todo these should be namespaced
#ifdef WINDOWS
typedef __int32 int32;
typedef __int64 int64;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
#elif HAVE_STDINT
#include <stdint.h>
typedef int32_t int32;
typedef int64_t int64;
typedef uint32_t uint32;
typedef uint64_t uint64;
#else
#error "Integer types not defined on this platform"
#endif

#include <stdexcept>
#include <string>

namespace zippylog {

/// The base zippylog exception
///
/// Zippylog code is expected to throw an exception derived from this for all
/// run-time errors. Zippylog code is allowed to throw exceptions derived from
/// std::logic_error if it makes sense (e.g. obvious coding error)
class ZIPPYLOG_EXPORT Exception : public ::std::runtime_error
{
public:
    /// Construct an exception from a string message
    ///
    /// @param msg Error message
    Exception(::std::string const &msg) : ::std::runtime_error(msg) { }
};

/// An error when deserializing a message
class ZIPPYLOG_EXPORT DeserializeException : public ::std::runtime_error
{
public:
    /// Construct an exception
    DeserializeException() : runtime_error("could not deserialize message") { }
};

/// Initializes the zippylog system
///
/// This should be called once at the beginning of every program/library that
/// uses zippylog.
///
/// The function is not thread safe.
ZIPPYLOG_EXPORT void initialize_library();

/// Runs zippylog shutdown procedures
/// This should be executed before process exit or when zippylog is no longer
/// needed by a process.
///
/// It isn't required to call this function. However, not doing so will result
/// in leaked memory (if the process lingers around). However, if the process
/// is terminating, it is safe to not call this function.
///
/// This function is not thread safe.
ZIPPYLOG_EXPORT void shutdown_library();

static const uint32 message_namespace = 1;

/// Default number of persisted state reactor threads for the server device
static const uint32 server_default_persisted_state_reactor_threads = 1;

/// Default number of worker threads for the server device
static const uint32 server_default_worker_threads = 2;

/// Default subscription TTL for server device (in milliseconds)
static const uint32 server_default_subscription_ttl = 60000;

/// Default stream flush interval for server device (in milliseconds)
static const uint32 server_default_stream_flush_interval = 5000;

/// Default bucket to log internal events to in server device
static const ::std::string server_default_log_bucket = "zippylog";

/// Default stream set to log internal events to in server device
static const ::std::string server_default_log_stream_set = "server";

/// Default value for whether to allow remote-supplied Lua code in server device
static const uint32 server_default_lua_allow = false;

/// Default maximum Lua allocation limit for streaming states, in bytes
static const uint32 server_default_lua_streaming_max_memory = 524288;

static const uint32 lua_default_subscription_memory_ceiling = 524288;

static const uint32 lua_default_plugin_memory_ceiling = 524288;

} // namespace

#endif
<|endoftext|>


<commit_before>#include "./labeller.h"
#include <Eigen/Geometry>
#include <QLoggingCategory>
#include <vector>
#include <map>
#include "../utils/cuda_array_provider.h"
#include "./summed_area_table.h"
#include "./apollonius.h"
#include "./occupancy_updater.h"
#include "./constraint_updater.h"

namespace Placement
{

QLoggingCategory plChan("Placement.Labeller");

Labeller::Labeller(std::shared_ptr<Labels> labels) : labels(labels)
{
}

void Labeller::initialize(
    std::shared_ptr<CudaArrayProvider> occupancyTextureMapper,
    std::shared_ptr<CudaArrayProvider> distanceTransformTextureMapper,
    std::shared_ptr<CudaArrayProvider> apolloniusTextureMapper,
    std::shared_ptr<ConstraintUpdater> constraintUpdater)
{
  qCInfo(plChan) << "Initialize";
  if (!occupancySummedAreaTable.get())
    occupancySummedAreaTable =
        std::make_shared<SummedAreaTable>(occupancyTextureMapper);
  occupancyUpdater = std::make_shared<OccupancyUpdater>(occupancyTextureMapper);

  this->distanceTransformTextureMapper = distanceTransformTextureMapper;
  this->apolloniusTextureMapper = apolloniusTextureMapper;
  this->constraintUpdater = constraintUpdater;

  costFunctionCalculator.setTextureSize(occupancyTextureMapper->getWidth(),
                                        occupancyTextureMapper->getHeight());
}

void Labeller::cleanup()
{
  occupancySummedAreaTable.reset();
  apolloniusTextureMapper.reset();
  occupancyUpdater.reset();
}

void Labeller::setInsertionOrder(std::vector<int> ids)
{
  insertionOrder = ids;
}

std::map<int, Eigen::Vector3f>
Labeller::update(const LabellerFrameData &frameData)
{
  newPositions.clear();
  if (!occupancySummedAreaTable.get())
    return newPositions;

  Eigen::Vector2i bufferSize(distanceTransformTextureMapper->getWidth(),
                             distanceTransformTextureMapper->getHeight());
  std::vector<Eigen::Vector4f> labelsSeed =
      createLabelSeeds(bufferSize, frameData.viewProjection);

  Apollonius apollonius(distanceTransformTextureMapper, apolloniusTextureMapper,
                        labelsSeed, labels->count());
  apollonius.run();
  setInsertionOrder(apollonius.calculateOrdering());

  Eigen::Matrix4f inverseViewProjection = frameData.viewProjection.inverse();

  // TODO(SIR): iterate through labels specific order according to apollonius.
  for (size_t i = 0; i < insertionOrder.size(); ++i)
  {
    int id = insertionOrder[i];
    occupancySummedAreaTable->runKernel();

    auto label = labels->getById(id);
    auto anchor2D = frameData.project(label.anchorPosition);
    float x = (anchor2D.x() * 0.5f + 0.5f) * width;
    float y = (anchor2D.y() * 0.5f + 0.5f) * height;

    std::cout << "x " << int(x) << " y " << int(y) << std::endl;
    Eigen::Vector2i labelSizeForBuffer =
        label.size.cast<int>().cwiseProduct(bufferSize).cwiseQuotient(
            Eigen::Vector2i(width, height));

    auto newPosition = costFunctionCalculator.calculateForLabel(
        occupancySummedAreaTable->getResults(), label.id, x, y, label.size.x(),
        label.size.y());

    float newXPosition = std::get<0>(newPosition);
    float newYPosition = std::get<1>(newPosition);

    occupancyUpdater->addLabel(newXPosition, newYPosition,
                               labelSizeForBuffer.x(), labelSizeForBuffer.y());

    if (i + 1 < insertionOrder.size())
    {
      int nextId = insertionOrder[i + 1];
      auto nextLabel = labels->getById(nextId);
      Eigen::Vector2i nextAnchor2D =
          toPixel(frameData.project(nextLabel.anchorPosition), bufferSize)
              .cast<int>();
      Eigen::Vector2i nextLabelSizeForBuffer =
          nextLabel.size.cast<int>().cwiseProduct(bufferSize).cwiseQuotient(
              Eigen::Vector2i(width, height));
      constraintUpdater->addLabel(
          nextAnchor2D.cast<int>(), nextLabelSizeForBuffer,
          toPixel(anchor2D, bufferSize).cast<int>(),
          Eigen::Vector2i(newXPosition, newYPosition), labelSizeForBuffer);
    }

    float newXNDC = (newXPosition / bufferSize.x() - 0.5f) * 2.0f;
    float newYNDC = (newYPosition / bufferSize.y() - 0.5f) * 2.0f;
    Eigen::Vector4f reprojected =
        inverseViewProjection *
        Eigen::Vector4f(newXNDC, newYNDC, anchor2D.z(), 1);
    reprojected /= reprojected.w();

    newPositions[label.id] = toVector3f(reprojected);
  }

  return newPositions;
}

void Labeller::resize(int width, int height)
{
  this->width = width;
  this->height = height;

  costFunctionCalculator.resize(width, height);
}

std::map<int, Eigen::Vector3f> Labeller::getLastPlacementResult()
{
  return newPositions;
}

std::vector<Eigen::Vector4f>
Labeller::createLabelSeeds(Eigen::Vector2i size, Eigen::Matrix4f viewProjection)
{
  std::vector<Eigen::Vector4f> result;
  for (auto &label : labels->getLabels())
  {
    Eigen::Vector4f pos =
        viewProjection * Eigen::Vector4f(label.anchorPosition.x(),
                                         label.anchorPosition.y(),
                                         label.anchorPosition.z(), 1);
    float x = (pos.x() / pos.w() * 0.5f + 0.5f) * size.x();
    float y = (pos.y() / pos.w() * 0.5f + 0.5f) * size.y();
    result.push_back(Eigen::Vector4f(label.id, x, y, 1));
  }

  return result;
}

Eigen::Vector2f Labeller::toPixel(Eigen::Vector3f ndc, Eigen::Vector2i size)
{
  const Eigen::Vector2f half(0.5f, 0.5f);

  auto zeroToOne = ndc.head<2>().cwiseProduct(half) + half;

  return zeroToOne.cwiseProduct(size.cast<float>());
}

}  // namespace Placement
<commit_msg>Prepare call to ConstraintUpdater so that it can be used for each label.<commit_after>#include "./labeller.h"
#include <Eigen/Geometry>
#include <QLoggingCategory>
#include <vector>
#include <map>
#include "../utils/cuda_array_provider.h"
#include "./summed_area_table.h"
#include "./apollonius.h"
#include "./occupancy_updater.h"
#include "./constraint_updater.h"

namespace Placement
{

QLoggingCategory plChan("Placement.Labeller");

Labeller::Labeller(std::shared_ptr<Labels> labels) : labels(labels)
{
}

void Labeller::initialize(
    std::shared_ptr<CudaArrayProvider> occupancyTextureMapper,
    std::shared_ptr<CudaArrayProvider> distanceTransformTextureMapper,
    std::shared_ptr<CudaArrayProvider> apolloniusTextureMapper,
    std::shared_ptr<ConstraintUpdater> constraintUpdater)
{
  qCInfo(plChan) << "Initialize";
  if (!occupancySummedAreaTable.get())
    occupancySummedAreaTable =
        std::make_shared<SummedAreaTable>(occupancyTextureMapper);
  occupancyUpdater = std::make_shared<OccupancyUpdater>(occupancyTextureMapper);

  this->distanceTransformTextureMapper = distanceTransformTextureMapper;
  this->apolloniusTextureMapper = apolloniusTextureMapper;
  this->constraintUpdater = constraintUpdater;

  costFunctionCalculator.setTextureSize(occupancyTextureMapper->getWidth(),
                                        occupancyTextureMapper->getHeight());
}

void Labeller::cleanup()
{
  occupancySummedAreaTable.reset();
  apolloniusTextureMapper.reset();
  occupancyUpdater.reset();
}

void Labeller::setInsertionOrder(std::vector<int> ids)
{
  insertionOrder = ids;
}

std::map<int, Eigen::Vector3f>
Labeller::update(const LabellerFrameData &frameData)
{
  newPositions.clear();
  if (!occupancySummedAreaTable.get())
    return newPositions;

  Eigen::Vector2i bufferSize(distanceTransformTextureMapper->getWidth(),
                             distanceTransformTextureMapper->getHeight());
  std::vector<Eigen::Vector4f> labelsSeed =
      createLabelSeeds(bufferSize, frameData.viewProjection);

  Apollonius apollonius(distanceTransformTextureMapper, apolloniusTextureMapper,
                        labelsSeed, labels->count());
  apollonius.run();
  setInsertionOrder(apollonius.calculateOrdering());

  Eigen::Matrix4f inverseViewProjection = frameData.viewProjection.inverse();

  std::map<int, Eigen::Vector2i> labelSizesForBuffer;
  std::map<int, Eigen::Vector2i> anchors2DForBuffer;
  std::map<int, Eigen::Vector2i> labelPositionsForBuffer;

  for (size_t i = 0; i < insertionOrder.size(); ++i)
  {
    int id = insertionOrder[i];
    occupancySummedAreaTable->runKernel();

    auto label = labels->getById(id);
    auto anchor2D = frameData.project(label.anchorPosition);
    float x = (anchor2D.x() * 0.5f + 0.5f) * width;
    float y = (anchor2D.y() * 0.5f + 0.5f) * height;

    std::cout << "x " << int(x) << " y " << int(y) << std::endl;
    Eigen::Vector2i labelSizeForBuffer =
        label.size.cast<int>().cwiseProduct(bufferSize).cwiseQuotient(
            Eigen::Vector2i(width, height));
    labelSizesForBuffer[id] = labelSizeForBuffer;

    Eigen::Vector2i anchor2DForBuffer =
        toPixel(anchor2D, bufferSize).cast<int>();
    anchors2DForBuffer[id] = anchor2DForBuffer;

    if (i == 3)
    for (size_t insertedLabelIndex = 0; insertedLabelIndex < i;
         ++insertedLabelIndex)
    {
      int oldId = insertionOrder[insertedLabelIndex];
      constraintUpdater->addLabel(
          anchor2DForBuffer, labelSizeForBuffer, anchors2DForBuffer[oldId],
          labelPositionsForBuffer[oldId], labelSizesForBuffer[oldId]);
    }

    auto newPosition = costFunctionCalculator.calculateForLabel(
        occupancySummedAreaTable->getResults(), label.id, x, y, label.size.x(),
        label.size.y());

    float newXPosition = std::get<0>(newPosition);
    float newYPosition = std::get<1>(newPosition);

    labelPositionsForBuffer[id] = Eigen::Vector2i(newXPosition, newYPosition);

    occupancyUpdater->addLabel(newXPosition, newYPosition,
                               labelSizeForBuffer.x(), labelSizeForBuffer.y());

    float newXNDC = (newXPosition / bufferSize.x() - 0.5f) * 2.0f;
    float newYNDC = (newYPosition / bufferSize.y() - 0.5f) * 2.0f;
    Eigen::Vector4f reprojected =
        inverseViewProjection *
        Eigen::Vector4f(newXNDC, newYNDC, anchor2D.z(), 1);
    reprojected /= reprojected.w();

    newPositions[label.id] = toVector3f(reprojected);
  }

  return newPositions;
}

void Labeller::resize(int width, int height)
{
  this->width = width;
  this->height = height;

  costFunctionCalculator.resize(width, height);
}

std::map<int, Eigen::Vector3f> Labeller::getLastPlacementResult()
{
  return newPositions;
}

std::vector<Eigen::Vector4f>
Labeller::createLabelSeeds(Eigen::Vector2i size, Eigen::Matrix4f viewProjection)
{
  std::vector<Eigen::Vector4f> result;
  for (auto &label : labels->getLabels())
  {
    Eigen::Vector4f pos =
        viewProjection * Eigen::Vector4f(label.anchorPosition.x(),
                                         label.anchorPosition.y(),
                                         label.anchorPosition.z(), 1);
    float x = (pos.x() / pos.w() * 0.5f + 0.5f) * size.x();
    float y = (pos.y() / pos.w() * 0.5f + 0.5f) * size.y();
    result.push_back(Eigen::Vector4f(label.id, x, y, 1));
  }

  return result;
}

Eigen::Vector2f Labeller::toPixel(Eigen::Vector3f ndc, Eigen::Vector2i size)
{
  const Eigen::Vector2f half(0.5f, 0.5f);

  auto zeroToOne = ndc.head<2>().cwiseProduct(half) + half;

  return zeroToOne.cwiseProduct(size.cast<float>());
}

}  // namespace Placement
<|endoftext|>


<commit_before>/****************************************************************************
 *   Copyright (C) 2013-2014 by Savoir-Faire Linux                           *
 *   Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> *
 *                                                                          *
 *   This library is free software; you can redistribute it and/or          *
 *   modify it under the terms of the GNU Lesser General Public             *
 *   License as published by the Free Software Foundation; either           *
 *   version 2.1 of the License, or (at your option) any later version.     *
 *                                                                          *
 *   This library is distributed in the hope that it will be useful,        *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
 *   Lesser General Public License for more details.                        *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/

#include "vcardutils.h"

//Qt
#include <QtCore/QBuffer>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QUrl>
#include <QtCore/QMimeData>

//Ring
#include "phonedirectorymodel.h"
#include "contactmethod.h"
#include "accountmodel.h"
#include "delegates/pixmapmanipulationdelegate.h"

/* https://www.ietf.org/rfc/rfc2045.txt
 * https://www.ietf.org/rfc/rfc2047.txt
 * https://www.ietf.org/rfc/rfc2426.txt
 */

//BEGIN:VCARD
//VERSION:3.0
//N:Gump;Forrest
//FN:Forrest Gump
//ORG:Bubba Gump Shrimp Co.
//TITLE:Shrimp Man
//PHOTO;VALUE=URL;TYPE=GIF:http://www.example.com/dir_photos/my_photo.gif
//TEL;TYPE=WORK,VOICE:(111) 555-1212
//TEL;TYPE=HOME,VOICE:(404) 555-1212
//ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
//LABEL;TYPE=WORK:100 Waters Edge\nBaytown, LA 30314\nUnited States of America
//ADR;TYPE=HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
//LABEL;TYPE=HOME:42 Plantation St.\nBaytown, LA 30314\nUnited States of America
//EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com
//REV:20080424T195243Z
//END:VCARD

struct VCardMapper;

typedef void (VCardMapper:: *mapToProperty)(Person*, const QString&, const QByteArray&);

struct VCardMapper {

   QHash<QByteArray, mapToProperty> m_hHash;

   VCardMapper() {
      m_hHash[VCardUtils::Property::UID] = &VCardMapper::setUid;
      m_hHash[VCardUtils::Property::NAME] = &VCardMapper::setNames;
      m_hHash[VCardUtils::Property::FORMATTED_NAME] = &VCardMapper::setFormattedName;
      m_hHash[VCardUtils::Property::EMAIL] = &VCardMapper::setEmail;
      m_hHash[VCardUtils::Property::ORGANIZATION] = &VCardMapper::setOrganization;
      m_hHash[VCardUtils::Property::TELEPHONE] = &VCardMapper::addContactMethod;
      m_hHash[VCardUtils::Property::ADDRESS] = &VCardMapper::addAddress;
      m_hHash[VCardUtils::Property::PHOTO] = &VCardMapper::setPhoto;
   }

   void setFormattedName(Person* c,  const QString&, const QByteArray& fn) {
      c->setFormattedName(QString::fromUtf8(fn));
   }

   void setNames(Person* c,  const QString&, const QByteArray& fn) {
      QList<QByteArray> splitted = fn.split(';');
      if (splitted.length() > 0)
         c->setFamilyName(splitted.at(0).trimmed());
      if (splitted.length() > 1)
         c->setFirstName(splitted.at(1).trimmed());
   }

   void setUid(Person* c,  const QString&, const QByteArray& fn) {
      c->setUid(fn);
   }

   void setEmail(Person* c,  const QString&, const QByteArray& fn) {
      c->setPreferredEmail(fn);
   }

   void setOrganization(Person* c, const QString&,  const QByteArray& fn) {
      c->setOrganization(QString::fromUtf8(fn));
   }

   void setPhoto(Person* c, const QString& key, const QByteArray& fn) {
      QByteArray type = "PNG";

      QRegExp rx("TYPE=([A-Za-z]*)");

      while ((rx.indexIn(key, 0)) != -1) {
         type = rx.cap(1).toLatin1();
         break;
      }

      QVariant photo = PixmapManipulationDelegate::instance()->personPhoto(fn,type);
      c->setPhoto(photo);
   }

   void addContactMethod(Person* c, const QString& key, const QByteArray& fn) {
      QByteArray type;

      QRegExp rx("TYPE=([A-Za-z,]*)");

      //VCard spec: it is RECOMMENDED that property and parameter names
      // be upper-case on output.
      rx.setCaseSensitivity(Qt::CaseInsensitive);

      while ((rx.indexIn(key, 0)) != -1) {
         type = rx.cap(1).toLatin1();
         break;
      }

      // TODO: Currently we only support one type (the first on the line) TYPE=WORK,VOICE: <number>
      const QStringList categories = QString(type).split(',');

      ContactMethod* cm = PhoneDirectoryModel::instance()->getNumber(fn,c,nullptr,categories.size()?categories[0]:QString());
      Person::ContactMethods m = c->phoneNumbers();
      m << cm;
      c->setContactMethods(m);
   }

   void addAddress(Person* c, const QString& key, const QByteArray& fn) {
      auto addr = Person::Address();
      QList<QByteArray> fields = fn.split(VCardUtils::Delimiter::SEPARATOR_TOKEN[0]);
      QStringList keyFields = key.split(VCardUtils::Delimiter::SEPARATOR_TOKEN);

      if(keyFields.size() < 2 || fields.size() < 7) {
          qDebug() << "Malformatted Address";
          return;
      }

      addr.setType        (keyFields[1]                   );
      addr.setAddressLine (QString::fromUtf8(fields[2])   );
      addr.setCity        (QString::fromUtf8(fields[3])   );
      addr.setState       (QString::fromUtf8(fields[4])   );
      addr.setZipCode     (QString::fromUtf8(fields[5])   );
      addr.setCountry     (QString::fromUtf8(fields[6])   );

      c->addAddress(addr);
   }

   bool metacall(Person* c, const QByteArray& key, const QByteArray& value) {
      const QStringList settings = QString(key).split(';');
      if (!m_hHash[settings[0].toLatin1()]) {
         if(key.contains(VCardUtils::Property::PHOTO)) {
            //key must contain additional attributes, we don't need them right now (ENCODING, TYPE...)
            setPhoto(c, key, value);
            return true;
         }

         if(key.contains(VCardUtils::Property::ADDRESS)) {
            addAddress(c, key, value);
            return true;
         }

         if(key.contains(VCardUtils::Property::TELEPHONE)) {
            addContactMethod(c, key, value);
            return true;
         }

         return false;
      }
      (this->*(m_hHash[settings[0].toLatin1()]))(c,key,value);
      return true;
   }
};
static VCardMapper* vc_mapper = new VCardMapper;

VCardUtils::VCardUtils()
{

}

void VCardUtils::startVCard(const QString& version)
{
   m_vCard << Delimiter::BEGIN_TOKEN;
   addProperty(Property::VERSION, version);
}

void VCardUtils::addProperty(const char* prop, const QString& value)
{
   if (value.isEmpty() || value == QString(';'))
      return;
   m_vCard << (QString::fromUtf8(prop) + ':' + value);
}

void VCardUtils::addProperty(const QString& prop, const QString& value)
{
   if (value.isEmpty() || value == QString(';'))
      return;
   m_vCard << (prop + ':' + value);
}

void VCardUtils::addEmail(const QString& type, const QString& email)
{
   addProperty(QString("%1%2%3%4").arg(Property::EMAIL).arg(Delimiter::SEPARATOR_TOKEN).arg("TYPE=").arg(type), email);
}

void VCardUtils::addAddress(const Person::Address& addr)
{
   QString prop = QString("%1%2%3").arg(Property::ADDRESS)
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.type());

   //First two fiels are left empty for now, they are for Postal box and Extended Address
   QString value = QString("%1%2%3%4%5%6%7%8%9%10%11")
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.addressLine())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.city())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.state())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.zipCode())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.country());

   addProperty(prop, value);
}

void VCardUtils::addContactMethod(const QString& type, const QString& num)
{
   QString prop = QString(Property::TELEPHONE) + QString(Delimiter::SEPARATOR_TOKEN) + type;
   addProperty(prop, num);
}

void VCardUtils::addPhoto(const QByteArray img)
{
   m_vCard << (QString::fromUtf8(Property::PHOTO) +
               QString::fromUtf8(Delimiter::SEPARATOR_TOKEN) +
               "ENCODING=BASE64" +
               QString::fromUtf8(Delimiter::SEPARATOR_TOKEN) +
               "TYPE=JPEG:")
           << " " << img.toBase64().trimmed();
}

const QByteArray VCardUtils::endVCard()
{
   m_vCard << Delimiter::END_TOKEN;
   const QString result = m_vCard.join(QString::fromUtf8(Delimiter::END_LINE_TOKEN));
   return result.toUtf8();
}

QList< Person* > VCardUtils::loadDir (const QUrl& path, bool& ok, QHash<const Person*,QString>& paths)
{
   QList< Person* > ret;

   QDir dir(path.toString());
   if (!dir.exists())
      ok = false;
   else {
      ok = true;
      for (const QString& file : dir.entryList({"*.vcf"},QDir::Files)) {
         Person* p = new Person();
         mapToPerson(p,QUrl(dir.absoluteFilePath(file)));
         ret << p;
         paths[p] = dir.absoluteFilePath(file);
      }
   }

   return ret;
}

bool VCardUtils::mapToPerson(Person* p, const QByteArray& all, QList<Account*>* accounts)
{
//    bool propertyInserted = false;
   QByteArray previousKey,previousValue;
   for (const QByteArray& property : all.split('\n')) {

      //Ignore empty lines
      if (property.size()) {

         //Some properties are over multiple lines
         if (property[0] == ' ' && previousKey.size()) {
            previousValue += property.right(property.size()-1);
         }
         else {
            if (previousKey.size()) {
               /*propertyInserted = */vc_mapper->metacall(p,previousKey,previousValue.trimmed());

//                if(!propertyInserted)
//                   qDebug() << "Could not extract: " << previousKey;
            }

            //Do not use split, URIs can have : in them
            const int dblptPos = property.indexOf(':');
            const QByteArray k(property.left(dblptPos)),v(property.right(property.size()-dblptPos-1));

            //Link with accounts
            if(k == VCardUtils::Property::X_RINGACCOUNT) {
                  if (accounts) {
                  Account* a = AccountModel::instance()->getById(v.trimmed(),true);
                  if(!a) {
                     qDebug() << "Could not find account: " << v.trimmed();
                     continue;
                  }

                  (*accounts) << a;
               }
            }

            previousKey   = k;
            previousValue = v;
         }

      }

   }
   return true;
}

bool VCardUtils::mapToPerson(Person* p, const QUrl& path, QList<Account*>* accounts)
{

   qDebug() << "file" << path.toString();

   QFile file(path.toString());
   if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
      qDebug() << "Error opening vcard: " << path;
      return false;
   }

   const QByteArray all = file.readAll();

   return mapToPerson(p,all,accounts);
}

//TODO get the daemon implementation, port it to Qt
QByteArray VCardUtils::wrapInMime(const QString& mimeType, const QByteArray& payload)
{
   QByteArray a;
   a += "MIME-Version: 1.0\n";
   a += "Content-Type: multipart/mixed; boundary=content\n";
   a += "\n";
   a += "--content\n";
   a += "Content-Type: "+mimeType+"\n";
   a += "\n";
   a += payload+"\n";
   a += "--content--\0";

   return a;
}

QMap<QString, QString> VCardUtils::parseMimeAttributes(const QString& mimeType)
{
    QMap<QString, QString> ret;

    const auto& list = mimeType.split(';');
    if (list.size() < 2)
        return {};

    const auto& pairs = list[1].split(',');
    for(const auto& p: pairs) {
        const auto& kv = p.split('=');
        ret[kv[0].trimmed()] = kv[1];
    }

    return ret;
}
<commit_msg>vcardutils: prevent potential index out of bounds<commit_after>/****************************************************************************
 *   Copyright (C) 2013-2014 by Savoir-Faire Linux                           *
 *   Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> *
 *                                                                          *
 *   This library is free software; you can redistribute it and/or          *
 *   modify it under the terms of the GNU Lesser General Public             *
 *   License as published by the Free Software Foundation; either           *
 *   version 2.1 of the License, or (at your option) any later version.     *
 *                                                                          *
 *   This library is distributed in the hope that it will be useful,        *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
 *   Lesser General Public License for more details.                        *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/

#include "vcardutils.h"

//Qt
#include <QtCore/QBuffer>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QUrl>
#include <QtCore/QMimeData>

//Ring
#include "phonedirectorymodel.h"
#include "contactmethod.h"
#include "accountmodel.h"
#include "delegates/pixmapmanipulationdelegate.h"

/* https://www.ietf.org/rfc/rfc2045.txt
 * https://www.ietf.org/rfc/rfc2047.txt
 * https://www.ietf.org/rfc/rfc2426.txt
 */

//BEGIN:VCARD
//VERSION:3.0
//N:Gump;Forrest
//FN:Forrest Gump
//ORG:Bubba Gump Shrimp Co.
//TITLE:Shrimp Man
//PHOTO;VALUE=URL;TYPE=GIF:http://www.example.com/dir_photos/my_photo.gif
//TEL;TYPE=WORK,VOICE:(111) 555-1212
//TEL;TYPE=HOME,VOICE:(404) 555-1212
//ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
//LABEL;TYPE=WORK:100 Waters Edge\nBaytown, LA 30314\nUnited States of America
//ADR;TYPE=HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
//LABEL;TYPE=HOME:42 Plantation St.\nBaytown, LA 30314\nUnited States of America
//EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com
//REV:20080424T195243Z
//END:VCARD

struct VCardMapper;

typedef void (VCardMapper:: *mapToProperty)(Person*, const QString&, const QByteArray&);

struct VCardMapper {

   QHash<QByteArray, mapToProperty> m_hHash;

   VCardMapper() {
      m_hHash[VCardUtils::Property::UID] = &VCardMapper::setUid;
      m_hHash[VCardUtils::Property::NAME] = &VCardMapper::setNames;
      m_hHash[VCardUtils::Property::FORMATTED_NAME] = &VCardMapper::setFormattedName;
      m_hHash[VCardUtils::Property::EMAIL] = &VCardMapper::setEmail;
      m_hHash[VCardUtils::Property::ORGANIZATION] = &VCardMapper::setOrganization;
      m_hHash[VCardUtils::Property::TELEPHONE] = &VCardMapper::addContactMethod;
      m_hHash[VCardUtils::Property::ADDRESS] = &VCardMapper::addAddress;
      m_hHash[VCardUtils::Property::PHOTO] = &VCardMapper::setPhoto;
   }

   void setFormattedName(Person* c,  const QString&, const QByteArray& fn) {
      c->setFormattedName(QString::fromUtf8(fn));
   }

   void setNames(Person* c,  const QString&, const QByteArray& fn) {
      QList<QByteArray> splitted = fn.split(';');
      if (splitted.length() > 0)
         c->setFamilyName(splitted.at(0).trimmed());
      if (splitted.length() > 1)
         c->setFirstName(splitted.at(1).trimmed());
   }

   void setUid(Person* c,  const QString&, const QByteArray& fn) {
      c->setUid(fn);
   }

   void setEmail(Person* c,  const QString&, const QByteArray& fn) {
      c->setPreferredEmail(fn);
   }

   void setOrganization(Person* c, const QString&,  const QByteArray& fn) {
      c->setOrganization(QString::fromUtf8(fn));
   }

   void setPhoto(Person* c, const QString& key, const QByteArray& fn) {
      QByteArray type = "PNG";

      QRegExp rx("TYPE=([A-Za-z]*)");

      while ((rx.indexIn(key, 0)) != -1) {
         type = rx.cap(1).toLatin1();
         break;
      }

      QVariant photo = PixmapManipulationDelegate::instance()->personPhoto(fn,type);
      c->setPhoto(photo);
   }

   void addContactMethod(Person* c, const QString& key, const QByteArray& fn) {
      QByteArray type;

      QRegExp rx("TYPE=([A-Za-z,]*)");

      //VCard spec: it is RECOMMENDED that property and parameter names
      // be upper-case on output.
      rx.setCaseSensitivity(Qt::CaseInsensitive);

      while ((rx.indexIn(key, 0)) != -1) {
         type = rx.cap(1).toLatin1();
         break;
      }

      // TODO: Currently we only support one type (the first on the line) TYPE=WORK,VOICE: <number>
      const QStringList categories = QString(type).split(',');

      ContactMethod* cm = PhoneDirectoryModel::instance()->getNumber(fn,c,nullptr,categories.size()?categories[0]:QString());
      Person::ContactMethods m = c->phoneNumbers();
      m << cm;
      c->setContactMethods(m);
   }

   void addAddress(Person* c, const QString& key, const QByteArray& fn) {
      auto addr = Person::Address();
      QList<QByteArray> fields = fn.split(VCardUtils::Delimiter::SEPARATOR_TOKEN[0]);
      QStringList keyFields = key.split(VCardUtils::Delimiter::SEPARATOR_TOKEN);

      if(keyFields.size() < 2 || fields.size() < 7) {
          qDebug() << "Malformatted Address";
          return;
      }

      addr.setType        (keyFields[1]                   );
      addr.setAddressLine (QString::fromUtf8(fields[2])   );
      addr.setCity        (QString::fromUtf8(fields[3])   );
      addr.setState       (QString::fromUtf8(fields[4])   );
      addr.setZipCode     (QString::fromUtf8(fields[5])   );
      addr.setCountry     (QString::fromUtf8(fields[6])   );

      c->addAddress(addr);
   }

   bool metacall(Person* c, const QByteArray& key, const QByteArray& value) {
      const QStringList settings = QString(key).split(';');
      if (settings.length() < 1)
         return false;

      if (!m_hHash[settings[0].toLatin1()]) {
         if(key.contains(VCardUtils::Property::PHOTO)) {
            //key must contain additional attributes, we don't need them right now (ENCODING, TYPE...)
            setPhoto(c, key, value);
            return true;
         }

         if(key.contains(VCardUtils::Property::ADDRESS)) {
            addAddress(c, key, value);
            return true;
         }

         if(key.contains(VCardUtils::Property::TELEPHONE)) {
            addContactMethod(c, key, value);
            return true;
         }

         return false;
      }
      (this->*(m_hHash[settings[0].toLatin1()]))(c,key,value);
      return true;
   }
};
static VCardMapper* vc_mapper = new VCardMapper;

VCardUtils::VCardUtils()
{

}

void VCardUtils::startVCard(const QString& version)
{
   m_vCard << Delimiter::BEGIN_TOKEN;
   addProperty(Property::VERSION, version);
}

void VCardUtils::addProperty(const char* prop, const QString& value)
{
   if (value.isEmpty() || value == QString(';'))
      return;
   m_vCard << (QString::fromUtf8(prop) + ':' + value);
}

void VCardUtils::addProperty(const QString& prop, const QString& value)
{
   if (value.isEmpty() || value == QString(';'))
      return;
   m_vCard << (prop + ':' + value);
}

void VCardUtils::addEmail(const QString& type, const QString& email)
{
   addProperty(QString("%1%2%3%4").arg(Property::EMAIL).arg(Delimiter::SEPARATOR_TOKEN).arg("TYPE=").arg(type), email);
}

void VCardUtils::addAddress(const Person::Address& addr)
{
   QString prop = QString("%1%2%3").arg(Property::ADDRESS)
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.type());

   //First two fiels are left empty for now, they are for Postal box and Extended Address
   QString value = QString("%1%2%3%4%5%6%7%8%9%10%11")
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.addressLine())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.city())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.state())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.zipCode())
         .arg(Delimiter::SEPARATOR_TOKEN)
         .arg(addr.country());

   addProperty(prop, value);
}

void VCardUtils::addContactMethod(const QString& type, const QString& num)
{
   QString prop = QString(Property::TELEPHONE) + QString(Delimiter::SEPARATOR_TOKEN) + type;
   addProperty(prop, num);
}

void VCardUtils::addPhoto(const QByteArray img)
{
   m_vCard << (QString::fromUtf8(Property::PHOTO) +
               QString::fromUtf8(Delimiter::SEPARATOR_TOKEN) +
               "ENCODING=BASE64" +
               QString::fromUtf8(Delimiter::SEPARATOR_TOKEN) +
               "TYPE=JPEG:")
           << " " << img.toBase64().trimmed();
}

const QByteArray VCardUtils::endVCard()
{
   m_vCard << Delimiter::END_TOKEN;
   const QString result = m_vCard.join(QString::fromUtf8(Delimiter::END_LINE_TOKEN));
   return result.toUtf8();
}

QList< Person* > VCardUtils::loadDir (const QUrl& path, bool& ok, QHash<const Person*,QString>& paths)
{
   QList< Person* > ret;

   QDir dir(path.toString());
   if (!dir.exists())
      ok = false;
   else {
      ok = true;
      for (const QString& file : dir.entryList({"*.vcf"},QDir::Files)) {
         Person* p = new Person();
         mapToPerson(p,QUrl(dir.absoluteFilePath(file)));
         ret << p;
         paths[p] = dir.absoluteFilePath(file);
      }
   }

   return ret;
}

bool VCardUtils::mapToPerson(Person* p, const QByteArray& all, QList<Account*>* accounts)
{
//    bool propertyInserted = false;
   QByteArray previousKey,previousValue;
   for (const QByteArray& property : all.split('\n')) {

      //Ignore empty lines
      if (property.size()) {

         //Some properties are over multiple lines
         if (property[0] == ' ' && previousKey.size()) {
            previousValue += property.right(property.size()-1);
         }
         else {
            if (previousKey.size()) {
               /*propertyInserted = */vc_mapper->metacall(p,previousKey,previousValue.trimmed());

//                if(!propertyInserted)
//                   qDebug() << "Could not extract: " << previousKey;
            }

            //Do not use split, URIs can have : in them
            const int dblptPos = property.indexOf(':');
            const QByteArray k(property.left(dblptPos)),v(property.right(property.size()-dblptPos-1));

            //Link with accounts
            if(k == VCardUtils::Property::X_RINGACCOUNT) {
                  if (accounts) {
                  Account* a = AccountModel::instance()->getById(v.trimmed(),true);
                  if(!a) {
                     qDebug() << "Could not find account: " << v.trimmed();
                     continue;
                  }

                  (*accounts) << a;
               }
            }

            previousKey   = k;
            previousValue = v;
         }

      }

   }
   return true;
}

bool VCardUtils::mapToPerson(Person* p, const QUrl& path, QList<Account*>* accounts)
{

   qDebug() << "file" << path.toString();

   QFile file(path.toString());
   if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
      qDebug() << "Error opening vcard: " << path;
      return false;
   }

   const QByteArray all = file.readAll();

   return mapToPerson(p,all,accounts);
}

//TODO get the daemon implementation, port it to Qt
QByteArray VCardUtils::wrapInMime(const QString& mimeType, const QByteArray& payload)
{
   QByteArray a;
   a += "MIME-Version: 1.0\n";
   a += "Content-Type: multipart/mixed; boundary=content\n";
   a += "\n";
   a += "--content\n";
   a += "Content-Type: "+mimeType+"\n";
   a += "\n";
   a += payload+"\n";
   a += "--content--\0";

   return a;
}

QMap<QString, QString> VCardUtils::parseMimeAttributes(const QString& mimeType)
{
    QMap<QString, QString> ret;

    const auto& list = mimeType.split(';');
    if (list.size() < 2)
        return {};

    const auto& pairs = list[1].split(',');
    for(const auto& p: pairs) {
        const auto& kv = p.split('=');
        ret[kv[0].trimmed()] = kv[1];
    }

    return ret;
}
<|endoftext|>


<commit_before>///
/// @file   int128.cpp
/// @brief  Test int128_t and uint128_t types.
///
/// Copyright (C) 2018 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <int128_t.hpp>

#include <stdint.h>
#include <cassert>
#include <iostream>
#include <type_traits>

using namespace std;
using namespace primecount;

#if defined(HAVE_INT128_T)

#include <cstdlib>
#include <sstream>
#include <string>

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

#endif

int main()
{
  static_assert(prt::numeric_limits<int8_t>::max() == std::numeric_limits<int8_t>::max(),
                "prt::numeric_limits<int8_t>::max() is broken");

  static_assert(prt::numeric_limits<uint64_t>::max() == std::numeric_limits<uint64_t>::max(),
                "prt::numeric_limits<uint64_t>::max() is broken");

  static_assert(prt::is_integral<uint64_t>::value,
                "prt::is_integral<uint64_t> != true");

  static_assert(!prt::is_integral<double>::value,
                "prt::is_integral<double> != false");

  static_assert(prt::is_signed<int64_t>::value,
                "prt::is_signed<int64_t> != true");

  static_assert(!prt::is_signed<uint64_t>::value,
                "prt::is_signed<uint64_t> != false");

  static_assert(!prt::is_unsigned<int64_t>::value,
                "prt::is_unsigned<int64_t> != false");

  static_assert(prt::is_unsigned<uint64_t>::value,
                "prt::is_unsigned<uint64_t> != true");

  static_assert(std::is_same<typename prt::make_signed<uint64_t>::type, int64_t>::value,
                "prt::make_signed<uint64_t> != int64_t");

#if defined(HAVE_INT128_T)
  static_assert(prt::numeric_limits<uint128_t>::max() == ~((uint128_t) 0),
                "prt::numeric_limits<uint128_t>::max() is broken");

  static_assert(prt::is_integral<int128_t>::value,
                "prt::is_integral<int128_t> != true");

  static_assert(prt::is_integral<uint128_t>::value,
                "prt::is_integral<uint128_t> != true");

  static_assert(prt::is_signed<int128_t>::value,
                "prt::is_signed<int128_t> != true");

  static_assert(!prt::is_signed<uint128_t>::value,
                "prt::is_signed<uint128_t> != false");

  static_assert(!prt::is_unsigned<int128_t>::value,
                "prt::is_unsigned<int128_t> != false");

  static_assert(prt::is_unsigned<uint128_t>::value,
                "prt::is_unsigned<uint128_t> != true");

  static_assert(std::is_same<typename prt::make_signed<int128_t>::type, int128_t>::value,
                "prt::make_signed<int128_t> != int128_t");

  static_assert(std::is_same<typename prt::make_signed<uint128_t>::type, int128_t>::value,
                "prt::make_signed<uint128_t> != int128_t");

  {
    ostringstream s;
    s << (((int128_t) 1 ) << 100);
    cout << "2^100 = " << s.str();
    check(s.str() == "1267650600228229401496703205376");
  }

  {
    ostringstream s;
    s << prt::numeric_limits<int128_t>::min();
    cout << "-2^127 = " << s.str();
    check(s.str() == "-170141183460469231731687303715884105728");
  }

  {
    ostringstream s;
    s << prt::numeric_limits<uint128_t>::max();
    cout << "2^128-1 = " << s.str();
    check(s.str() == "340282366920938463463374607431768211455");
  }
#endif

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<commit_msg>Refactor<commit_after>///
/// @file   int128.cpp
/// @brief  Test int128_t and uint128_t types.
///
/// Copyright (C) 2018 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <int128_t.hpp>

#include <stdint.h>
#include <cassert>
#include <iostream>
#include <type_traits>

using namespace std;
using namespace primecount;

#if defined(HAVE_INT128_T)

#include <cstdlib>
#include <sstream>
#include <string>

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

#endif

int main()
{
  static_assert(prt::numeric_limits<int8_t>::max() == std::numeric_limits<int8_t>::max(),
                "prt::numeric_limits<int8_t>::max() is broken");

  static_assert(prt::numeric_limits<uint64_t>::max() == std::numeric_limits<uint64_t>::max(),
                "prt::numeric_limits<uint64_t>::max() is broken");

  static_assert(prt::is_integral<uint64_t>::value,
                "prt::is_integral<uint64_t> != true");

  static_assert(!prt::is_integral<double>::value,
                "prt::is_integral<double> != false");

  static_assert(prt::is_signed<int64_t>::value,
                "prt::is_signed<int64_t> != true");

  static_assert(!prt::is_signed<uint64_t>::value,
                "prt::is_signed<uint64_t> != false");

  static_assert(!prt::is_unsigned<int64_t>::value,
                "prt::is_unsigned<int64_t> != false");

  static_assert(prt::is_unsigned<uint64_t>::value,
                "prt::is_unsigned<uint64_t> != true");

  static_assert(std::is_same<typename prt::make_signed<uint64_t>::type, int64_t>::value,
                "prt::make_signed<uint64_t> != int64_t");

#if defined(HAVE_INT128_T)

  static_assert(prt::numeric_limits<uint128_t>::max() == ~((uint128_t) 0),
                "prt::numeric_limits<uint128_t>::max() is broken");

  static_assert(prt::is_integral<int128_t>::value,
                "prt::is_integral<int128_t> != true");

  static_assert(prt::is_integral<uint128_t>::value,
                "prt::is_integral<uint128_t> != true");

  static_assert(prt::is_signed<int128_t>::value,
                "prt::is_signed<int128_t> != true");

  static_assert(!prt::is_signed<uint128_t>::value,
                "prt::is_signed<uint128_t> != false");

  static_assert(!prt::is_unsigned<int128_t>::value,
                "prt::is_unsigned<int128_t> != false");

  static_assert(prt::is_unsigned<uint128_t>::value,
                "prt::is_unsigned<uint128_t> != true");

  static_assert(std::is_same<typename prt::make_signed<int128_t>::type, int128_t>::value,
                "prt::make_signed<int128_t> != int128_t");

  static_assert(std::is_same<typename prt::make_signed<uint128_t>::type, int128_t>::value,
                "prt::make_signed<uint128_t> != int128_t");

  {
    ostringstream s;
    s << (((int128_t) 1 ) << 100);
    cout << "2^100 = " << s.str();
    check(s.str() == "1267650600228229401496703205376");
  }

  {
    ostringstream s;
    s << prt::numeric_limits<int128_t>::min();
    cout << "-2^127 = " << s.str();
    check(s.str() == "-170141183460469231731687303715884105728");
  }

  {
    ostringstream s;
    s << prt::numeric_limits<uint128_t>::max();
    cout << "2^128-1 = " << s.str();
    check(s.str() == "340282366920938463463374607431768211455");
  }

#endif

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<|endoftext|>