<commit_before>/*
 * Copyright (C) 2017 Fondazione Istituto Italiano di Tecnologia
 * Authors: Silvio Traversaro
 * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
 *
 */

#include <iDynTree/InverseKinematics.h>
#include <iDynTree/KinDynComputations.h>

#include <iDynTree/Core/TestUtils.h>
#include <iDynTree/Model/JointState.h>
#include <iDynTree/Model/ModelTestUtils.h>

#include "testModels.h"

#include <cstdio>
#include <cstdlib>

#include <ctime>

/**
 * Return the current time in seconds, with respect
 * to an arbitrary point in time.
 */
inline double clockInSec()
{
    clock_t ret = clock();
    return ((double)ret)/((double)CLOCKS_PER_SEC);
}

iDynTree::JointPosDoubleArray getRandomJointPositions(const iDynTree::Model & model)
{
    iDynTree::JointPosDoubleArray sRandom(model);
    getRandomJointPositions(sRandom,model);
    return sRandom;
}

inline iDynTree::JointPosDoubleArray getRandomJointPositionsCloseTo(const iDynTree::Model& model, iDynTree::VectorDynSize s, double maxDelta)
{
    iDynTree::JointPosDoubleArray vec(model);

    assert(vec.size() == model.getNrOfPosCoords());
    for(iDynTree::JointIndex jntIdx=0; jntIdx < model.getNrOfJoints(); jntIdx++)
    {
        iDynTree::IJointConstPtr jntPtr = model.getJoint(jntIdx);
        if( jntPtr->hasPosLimits() )
        {
            for(int i=0; i < jntPtr->getNrOfPosCoords(); i++)
            {
                int dofIndex = jntPtr->getDOFsOffset()+i;
                double max = std::min(jntPtr->getMaxPosLimit(i),s(dofIndex)+maxDelta);
                double min = std::max(jntPtr->getMinPosLimit(i),s(dofIndex)-maxDelta);
                vec(dofIndex) = iDynTree::getRandomDouble(min,max);
            }
        }
        else
        {
            for(int i=0; i < jntPtr->getNrOfPosCoords(); i++)
            {
                int dofIndex = jntPtr->getDOFsOffset()+i;
                vec(jntPtr->getDOFsOffset()+i) = iDynTree::getRandomDouble(s(dofIndex)-maxDelta,s(dofIndex)+maxDelta);
            }
        }
    }

    return vec;
}

struct simpleChainIKOptions
{
    iDynTree::InverseKinematicsRotationParametrization rotationParametrization;
    bool useDesiredJointPositionsToActualValue;
    bool useDesiredJointPositionsToRandomValue;
};

void simpleChainIK(int minNrOfJoints, int maxNrOfJoints, const iDynTree::InverseKinematicsRotationParametrization rotationParametrization)
{
    // Solve a simple IK problem for a chain, with no constraints
    for (int i = minNrOfJoints; i <= maxNrOfJoints; i++)
    {
        assert(i >= 2);

        std::cerr << "~~~~~~~> simpleChainIK with " << i << " dofs " << std::endl;
        bool noFixedJoints = true;
        iDynTree::Model chain = iDynTree::getRandomChain(i,10,noFixedJoints);

        ASSERT_EQUAL_DOUBLE(i, chain.getNrOfDOFs());

        // Name of the targetFrame the leaf added by getRandomChain
        std::string targetFrame = "link" + iDynTree::int2string(i - 1);

        // Create IK
        iDynTree::InverseKinematics ik;
        bool ok = ik.setModel(chain);
        ASSERT_IS_TRUE(ok);
        // Always express the target as cost
        ik.setTargetResolutionMode(iDynTree::InverseKinematicsTreatTargetAsConstraintNone);

        // Use the requested parametrization
        ik.setRotationParametrization(rotationParametrization);

        ik.setTol(1e-6);
        ik.setConstrTol(1e-7);

        // Create also a KinDyn object to perform forward kinematics for the desired values and the optimized ones
        iDynTree::KinDynComputations kinDynDes;
        ok = kinDynDes.loadRobotModel(ik.model());
        ASSERT_IS_TRUE(ok);
        iDynTree::KinDynComputations kinDynOpt;
        ok = kinDynOpt.loadRobotModel(ik.model());
        ASSERT_IS_TRUE(ok);

        // Create a random vector of internal joint positions
        // used to get reasonable values for the constraints and the targets
        iDynTree::JointPosDoubleArray s = getRandomJointPositions(kinDynDes.model());
        ok = kinDynDes.setJointPos(s);
        ASSERT_IS_TRUE(ok);

        // Add the fixed base constraint
        ok = ik.addFrameConstraint("link1", kinDynDes.getWorldTransform("link1"));
        //ok = ik.addFrameRotationConstraint("link1", iDynTree::Transform::Identity().getRotation());
        //ok = ik.addFramePositionConstraint("link1", iDynTree::Transform::Identity().getPosition());
        ASSERT_IS_TRUE(ok);

        // Add target
        ok = ik.addPositionTarget(targetFrame, kinDynDes.getWorldTransform(targetFrame));
        ASSERT_IS_TRUE(ok);

        // Add a random initial guess
        iDynTree::Transform baseDes = kinDynDes.getWorldBaseTransform();
        // Set a max delta to avoid local minima in testing
        double maxDelta = 0.01;
        iDynTree::JointPosDoubleArray sInitial = getRandomJointPositionsCloseTo(ik.model(),s,maxDelta);
        ik.setInitialCondition(&(baseDes),&(sInitial));

        // Add a random desired position
        iDynTree::JointPosDoubleArray sDesired = getRandomJointPositions(ik.model());
        ik.setDesiredJointConfiguration(sDesired,1e-12);

        // Start from the initial one
        double tic = clockInSec();
        ok = ik.solve();
        double toc = clockInSec();

        ASSERT_IS_TRUE(ok);

        // Get the solution
        iDynTree::Transform baseOpt = iDynTree::Transform::Identity();
        iDynTree::JointPosDoubleArray sOpt(ik.model());
        ik.getSolution(baseOpt,sOpt);
        iDynTree::Twist dummyVel;
        dummyVel.zero();
        iDynTree::Vector3 dummyGrav;
        dummyGrav.zero();
        iDynTree::JointDOFsDoubleArray dummyJointVel(ik.model());
        dummyJointVel.zero();

        kinDynOpt.setRobotState(baseOpt,sOpt,dummyVel,dummyJointVel,dummyGrav);
        double tolConstraints = 1e-6;
        double tolTargets     = 1e-3;

        // Check if the base link constraint is still valid
        ASSERT_EQUAL_TRANSFORM_TOL(kinDynOpt.getWorldTransform("link1"), kinDynDes.getWorldTransform("link1"), tolConstraints);

        // Check if the target is realized
        ASSERT_EQUAL_VECTOR_TOL(kinDynDes.getWorldTransform(targetFrame).getPosition(), kinDynOpt.getWorldTransform(targetFrame).getPosition(), tolTargets);
    }

}

// Check the consistency of a simple humanoid wholebody IK test case
void simpleHumanoidWholeBodyIKConsistency(const iDynTree::InverseKinematicsRotationParametrization rotationParametrization)
{
    iDynTree::InverseKinematics ik;

    bool ok = ik.loadModelFromFile(getAbsModelPath("iCubGenova02.urdf"));
    ASSERT_IS_TRUE(ok);

    //ik.setFloatingBaseOnFrameNamed("l_foot");

    ik.setRotationParametrization(rotationParametrization);

    // Create also a KinDyn object to perform forward kinematics for the desired values
    iDynTree::KinDynComputations kinDynDes;
    ok = kinDynDes.loadRobotModel(ik.model());
    ASSERT_IS_TRUE(ok);

    // Create a random vector of internal joint positions
    // used to get reasonable values for the constraints and the targets
    iDynTree::JointPosDoubleArray s = getRandomJointPositions(kinDynDes.model());
    ok = kinDynDes.setJointPos(s);
    ASSERT_IS_TRUE(ok);

    // Create a simple IK problem with the foot constraint

    // The l_sole frame is our world absolute frame (i.e. {}^A H_{l_sole} = identity
    ok = ik.addFrameConstraint("l_foot",kinDynDes.getWorldTransform("l_foot"));
    ASSERT_IS_TRUE(ok);

    std::cerr << "kinDynDes.getWorldTransform(l_foot) : " << kinDynDes.getWorldTransform("l_foot").toString() << std::endl;

    // The relative position of the r_sole should be the initial one
    ok = ik.addFrameConstraint("r_sole",kinDynDes.getWorldTransform("r_sole"));
    ASSERT_IS_TRUE(ok);

    // The two cartesian targets should be reasonable values
    ik.setTargetResolutionMode(iDynTree::InverseKinematicsTreatTargetAsConstraintNone);
    ok = ik.addPositionTarget("l_elbow_1",kinDynDes.getWorldTransform("l_elbow_1"));
    ASSERT_IS_TRUE(ok);

    //ok = ik.addPositionTarget("r_elbow_1",kinDynDes.getRelativeTransform("l_sole","r_elbow_1").getPosition());
    //ASSERT_IS_TRUE(ok);

    iDynTree::Transform initialH = kinDynDes.getWorldBaseTransform();

    ik.setInitialCondition(&initialH,&s);
    ik.setDesiredJointConfiguration(s,1e-15);

    // Solve the optimization problem
    double tic = clockInSec();
    ok = ik.solve();
    double toc = clockInSec();
    std::cerr << "Inverse Kinematics solved in " << toc-tic << " seconds. " << std::endl;
    ASSERT_IS_TRUE(ok);

    iDynTree::Transform basePosOptimized;
    iDynTree::JointPosDoubleArray sOptimized(ik.model());
    sOptimized.zero();

    ik.getSolution(basePosOptimized,sOptimized);

    // We create a new KinDyn object to perform forward kinematics for the optimized values
    iDynTree::KinDynComputations kinDynOpt;
    kinDynOpt.loadRobotModel(ik.model());
    iDynTree::Twist dummyVel;
    dummyVel.zero();
    iDynTree::Vector3 dummyGrav;
    dummyGrav.zero();
    iDynTree::JointDOFsDoubleArray dummyJointVel(ik.model());
    dummyJointVel.zero();
    kinDynOpt.setRobotState(basePosOptimized, sOptimized, dummyVel, dummyJointVel, dummyGrav);

    // Check that the contraint and the targets are respected
    double tolConstraints = 1e-7;
    double tolTargets     = 1e-6;
    ASSERT_EQUAL_TRANSFORM_TOL(kinDynDes.getWorldTransform("l_foot"),kinDynOpt.getWorldTransform("l_foot"),tolConstraints);
    ASSERT_EQUAL_TRANSFORM_TOL(kinDynDes.getWorldTransform("r_sole"),kinDynOpt.getWorldTransform("r_sole"),tolConstraints);
    ASSERT_EQUAL_VECTOR_TOL(kinDynDes.getWorldTransform("l_elbow_1").getPosition(),
                            kinDynOpt.getWorldTransform("l_elbow_1").getPosition(),tolTargets);

    return;
}

int main()
{
    // Improve repetability (at least in the same platform)
    srand(0);

    simpleChainIK(2,13,iDynTree::InverseKinematicsRotationParametrizationRollPitchYaw);

    // This is not working at the moment, there is some problem with quaternion constraints
    //simpleChainIK(10,iDynTree::InverseKinematicsRotationParametrizationQuaternion);

    simpleHumanoidWholeBodyIKConsistency(iDynTree::InverseKinematicsRotationParametrizationRollPitchYaw);

    return EXIT_SUCCESS;
}
<commit_msg>Updated unit test<commit_after>/*
 * Copyright (C) 2017 Fondazione Istituto Italiano di Tecnologia
 * Authors: Silvio Traversaro
 * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
 *
 */

#include <iDynTree/InverseKinematics.h>
#include <iDynTree/KinDynComputations.h>

#include <iDynTree/Core/TestUtils.h>
#include <iDynTree/Model/JointState.h>
#include <iDynTree/Model/ModelTestUtils.h>

#include "testModels.h"

#include <cstdio>
#include <cstdlib>

#include <ctime>

/**
 * Return the current time in seconds, with respect
 * to an arbitrary point in time.
 */
inline double clockInSec()
{
    clock_t ret = clock();
    return ((double)ret)/((double)CLOCKS_PER_SEC);
}

iDynTree::JointPosDoubleArray getRandomJointPositions(const iDynTree::Model & model)
{
    iDynTree::JointPosDoubleArray sRandom(model);
    getRandomJointPositions(sRandom,model);
    return sRandom;
}

inline iDynTree::JointPosDoubleArray getRandomJointPositionsCloseTo(const iDynTree::Model& model, iDynTree::VectorDynSize s, double maxDelta)
{
    iDynTree::JointPosDoubleArray vec(model);

    assert(vec.size() == model.getNrOfPosCoords());
    for(iDynTree::JointIndex jntIdx=0; jntIdx < model.getNrOfJoints(); jntIdx++)
    {
        iDynTree::IJointConstPtr jntPtr = model.getJoint(jntIdx);
        if( jntPtr->hasPosLimits() )
        {
            for(int i=0; i < jntPtr->getNrOfPosCoords(); i++)
            {
                int dofIndex = jntPtr->getDOFsOffset()+i;
                double max = std::min(jntPtr->getMaxPosLimit(i),s(dofIndex)+maxDelta);
                double min = std::max(jntPtr->getMinPosLimit(i),s(dofIndex)-maxDelta);
                vec(dofIndex) = iDynTree::getRandomDouble(min,max);
            }
        }
        else
        {
            for(int i=0; i < jntPtr->getNrOfPosCoords(); i++)
            {
                int dofIndex = jntPtr->getDOFsOffset()+i;
                vec(jntPtr->getDOFsOffset()+i) = iDynTree::getRandomDouble(s(dofIndex)-maxDelta,s(dofIndex)+maxDelta);
            }
        }
    }

    return vec;
}

struct simpleChainIKOptions
{
    iDynTree::InverseKinematicsRotationParametrization rotationParametrization;
    bool useDesiredJointPositionsToActualValue;
    bool useDesiredJointPositionsToRandomValue;
};

void simpleChainIK(int minNrOfJoints, int maxNrOfJoints, const iDynTree::InverseKinematicsRotationParametrization rotationParametrization)
{
    // Solve a simple IK problem for a chain, with no constraints
    for (int i = minNrOfJoints; i <= maxNrOfJoints; i++)
    {
        assert(i >= 2);

        std::cerr << "~~~~~~~> simpleChainIK with " << i << " dofs " << std::endl;
        bool noFixedJoints = true;
        iDynTree::Model chain = iDynTree::getRandomChain(i,10,noFixedJoints);

        ASSERT_EQUAL_DOUBLE(i, chain.getNrOfDOFs());

        // Name of the targetFrame the leaf added by getRandomChain
        std::string targetFrame = "link" + iDynTree::int2string(i - 1);

        // Create IK
        iDynTree::InverseKinematics ik;
        bool ok = ik.setModel(chain);
        ASSERT_IS_TRUE(ok);
        // Always express the target as cost
        ik.setTargetResolutionMode(iDynTree::InverseKinematicsTreatTargetAsConstraintNone);

        // Use the requested parametrization
        ik.setRotationParametrization(rotationParametrization);

        ik.setTol(1e-6);
        ik.setConstrTol(1e-7);

        // Create also a KinDyn object to perform forward kinematics for the desired values and the optimized ones
        iDynTree::KinDynComputations kinDynDes;
        ok = kinDynDes.loadRobotModel(ik.model());
        ASSERT_IS_TRUE(ok);
        iDynTree::KinDynComputations kinDynOpt;
        ok = kinDynOpt.loadRobotModel(ik.model());
        ASSERT_IS_TRUE(ok);

        // Create a random vector of internal joint positions
        // used to get reasonable values for the constraints and the targets
        iDynTree::JointPosDoubleArray s = getRandomJointPositions(kinDynDes.model());
        ok = kinDynDes.setJointPos(s);
        ASSERT_IS_TRUE(ok);

        // Add the fixed base constraint
        ok = ik.addFrameConstraint("link1", kinDynDes.getWorldTransform("link1"));
        //ok = ik.addFrameRotationConstraint("link1", iDynTree::Transform::Identity().getRotation());
        //ok = ik.addFramePositionConstraint("link1", iDynTree::Transform::Identity().getPosition());
        ASSERT_IS_TRUE(ok);

        // Add target
        ok = ik.addPositionTarget(targetFrame, kinDynDes.getWorldTransform(targetFrame));
        ASSERT_IS_TRUE(ok);

        // Add a random initial guess
        iDynTree::Transform baseDes = kinDynDes.getWorldBaseTransform();
        // Set a max delta to avoid local minima in testing
        double maxDelta = 0.01;
        iDynTree::JointPosDoubleArray sInitial = getRandomJointPositionsCloseTo(ik.model(),s,maxDelta);
        ik.setInitialCondition(&(baseDes),&(sInitial));

        // Add a random desired position
        iDynTree::JointPosDoubleArray sDesired = getRandomJointPositions(ik.model());
        ik.setDesiredJointConfiguration(sDesired,1e-12);

        // Start from the initial one
        double tic = clockInSec();
        ok = ik.solve();
        double toc = clockInSec();

        ASSERT_IS_TRUE(ok);

        // Get the solution
        iDynTree::Transform baseOpt = iDynTree::Transform::Identity();
        iDynTree::JointPosDoubleArray sOpt(ik.model());
        ik.getSolution(baseOpt,sOpt);
        iDynTree::Twist dummyVel;
        dummyVel.zero();
        iDynTree::Vector3 dummyGrav;
        dummyGrav.zero();
        iDynTree::JointDOFsDoubleArray dummyJointVel(ik.model());
        dummyJointVel.zero();

        kinDynOpt.setRobotState(baseOpt,sOpt,dummyVel,dummyJointVel,dummyGrav);
        double tolConstraints = 1e-6;
        double tolTargets     = 1e-3;

        // Check if the base link constraint is still valid
        ASSERT_EQUAL_TRANSFORM_TOL(kinDynOpt.getWorldTransform("link1"), kinDynDes.getWorldTransform("link1"), tolConstraints);

        // Check if the target is realized
        ASSERT_EQUAL_VECTOR_TOL(kinDynDes.getWorldTransform(targetFrame).getPosition(), kinDynOpt.getWorldTransform(targetFrame).getPosition(), tolTargets);
    }

}

// Check the consistency of a simple humanoid wholebody IK test case
void simpleHumanoidWholeBodyIKConsistency(const iDynTree::InverseKinematicsRotationParametrization rotationParametrization)
{
    iDynTree::InverseKinematics ik;

    bool ok = ik.loadModelFromFile(getAbsModelPath("iCubGenova02.urdf"));
    ASSERT_IS_TRUE(ok);

    //ik.setFloatingBaseOnFrameNamed("l_foot");

    ik.setRotationParametrization(rotationParametrization);

    // Create also a KinDyn object to perform forward kinematics for the desired values
    iDynTree::KinDynComputations kinDynDes;
    ok = kinDynDes.loadRobotModel(ik.model());
    ASSERT_IS_TRUE(ok);

    // Create a random vector of internal joint positions
    // used to get reasonable values for the constraints and the targets
    iDynTree::JointPosDoubleArray s = getRandomJointPositions(kinDynDes.model());
    ok = kinDynDes.setJointPos(s);
    ASSERT_IS_TRUE(ok);

    // Create a simple IK problem with the foot constraint

    // The l_sole frame is our world absolute frame (i.e. {}^A H_{l_sole} = identity
    ok = ik.addFrameConstraint("l_foot",kinDynDes.getWorldTransform("l_foot"));
    ASSERT_IS_TRUE(ok);

    std::cerr << "kinDynDes.getWorldTransform(l_foot) : " << kinDynDes.getWorldTransform("l_foot").toString() << std::endl;

    // The relative position of the r_sole should be the initial one
    ok = ik.addFrameConstraint("r_sole",kinDynDes.getWorldTransform("r_sole"));
    ASSERT_IS_TRUE(ok);

    // The two cartesian targets should be reasonable values
    ik.setTargetResolutionMode(iDynTree::InverseKinematicsTreatTargetAsConstraintNone);
    ok = ik.addPositionTarget("l_elbow_1",kinDynDes.getWorldTransform("l_elbow_1"));
    ASSERT_IS_TRUE(ok);

    //ok = ik.addPositionTarget("r_elbow_1",kinDynDes.getRelativeTransform("l_sole","r_elbow_1").getPosition());
    //ASSERT_IS_TRUE(ok);

    iDynTree::Transform initialH = kinDynDes.getWorldBaseTransform();

    ik.setInitialCondition(&initialH,&s);
    ik.setDesiredJointConfiguration(s,1e-15);

    // Solve the optimization problem
    double tic = clockInSec();
    ok = ik.solve();
    double toc = clockInSec();
    std::cerr << "Inverse Kinematics solved in " << toc-tic << " seconds. " << std::endl;
    ASSERT_IS_TRUE(ok);

    iDynTree::Transform basePosOptimized;
    iDynTree::JointPosDoubleArray sOptimized(ik.model());
    sOptimized.zero();

    ik.getSolution(basePosOptimized,sOptimized);

    // We create a new KinDyn object to perform forward kinematics for the optimized values
    iDynTree::KinDynComputations kinDynOpt;
    kinDynOpt.loadRobotModel(ik.model());
    iDynTree::Twist dummyVel;
    dummyVel.zero();
    iDynTree::Vector3 dummyGrav;
    dummyGrav.zero();
    iDynTree::JointDOFsDoubleArray dummyJointVel(ik.model());
    dummyJointVel.zero();
    kinDynOpt.setRobotState(basePosOptimized, sOptimized, dummyVel, dummyJointVel, dummyGrav);

    // Check that the contraint and the targets are respected
    double tolConstraints = 1e-7;
    double tolTargets     = 1e-6;
    ASSERT_EQUAL_TRANSFORM_TOL(kinDynDes.getWorldTransform("l_foot"),kinDynOpt.getWorldTransform("l_foot"),tolConstraints);
    ASSERT_EQUAL_TRANSFORM_TOL(kinDynDes.getWorldTransform("r_sole"),kinDynOpt.getWorldTransform("r_sole"),tolConstraints);
    ASSERT_EQUAL_VECTOR_TOL(kinDynDes.getWorldTransform("l_elbow_1").getPosition(),
                            kinDynOpt.getWorldTransform("l_elbow_1").getPosition(),tolTargets);

    return;
}

// Check the consistency of a simple humanoid wholebody IK test case, setting a CoM target.
void simpleHumanoidWholeBodyIKCoMConsistency(const iDynTree::InverseKinematicsRotationParametrization rotationParametrization,
                                             const iDynTree::InverseKinematicsTreatTargetAsConstraint targetResolutionMode)
{
    iDynTree::InverseKinematics ik;

    bool ok = ik.loadModelFromFile(getAbsModelPath("iCubGenova02.urdf"));
    ASSERT_IS_TRUE(ok);

    //ik.setFloatingBaseOnFrameNamed("l_foot");

    ik.setRotationParametrization(rotationParametrization);

    // Create also a KinDyn object to perform forward kinematics for the desired values
    iDynTree::KinDynComputations kinDynDes;
    ok = kinDynDes.loadRobotModel(ik.model());
    ASSERT_IS_TRUE(ok);

    // Create a random vector of internal joint positions
    // used to get reasonable values for the constraints and the targets
    iDynTree::JointPosDoubleArray s = getRandomJointPositions(kinDynDes.model());
    ok = kinDynDes.setJointPos(s);
    ASSERT_IS_TRUE(ok);

    // Create a simple IK problem with the foot constraint

    // The l_sole frame is our world absolute frame (i.e. {}^A H_{l_sole} = identity
    ok = ik.addFrameConstraint("l_foot",kinDynDes.getWorldTransform("l_foot"));
    ASSERT_IS_TRUE(ok);

    std::cerr << "kinDynDes.getWorldTransform(l_foot) : " << kinDynDes.getWorldTransform("l_foot").toString() << std::endl;

    // The relative position of the r_sole should be the initial one
    ok = ik.addFrameConstraint("r_sole",kinDynDes.getWorldTransform("r_sole"));
    ASSERT_IS_TRUE(ok);

    // The two cartesian targets should be reasonable values
    ik.setTargetResolutionMode(targetResolutionMode);
    iDynTree::Position comDes = kinDynDes.getCenterOfMassPosition();
    ik.setCoMTarget(comDes);

    //ok = ik.addPositionTarget("r_elbow_1",kinDynDes.getRelativeTransform("l_sole","r_elbow_1").getPosition());
    //ASSERT_IS_TRUE(ok);

    iDynTree::Transform initialH = kinDynDes.getWorldBaseTransform();

    ik.setInitialCondition(&initialH,&s);
    ik.setDesiredJointConfiguration(s,1e-15);

    // Solve the optimization problem
    double tic = clockInSec();
    ok = ik.solve();
    double toc = clockInSec();
    std::cerr << "Inverse Kinematics solved in " << toc-tic << " seconds. " << std::endl;
    ASSERT_IS_TRUE(ok);

    iDynTree::Transform basePosOptimized;
    iDynTree::JointPosDoubleArray sOptimized(ik.model());
    sOptimized.zero();

    ik.getSolution(basePosOptimized,sOptimized);

    // We create a new KinDyn object to perform forward kinematics for the optimized values
    iDynTree::KinDynComputations kinDynOpt;
    kinDynOpt.loadRobotModel(ik.model());
    iDynTree::Twist dummyVel;
    dummyVel.zero();
    iDynTree::Vector3 dummyGrav;
    dummyGrav.zero();
    iDynTree::JointDOFsDoubleArray dummyJointVel(ik.model());
    dummyJointVel.zero();
    kinDynOpt.setRobotState(basePosOptimized, sOptimized, dummyVel, dummyJointVel, dummyGrav);

    // Check that the contraint and the targets are respected
    double tolConstraints = 1e-7;
    double tolTargets     = 1e-6;
    ASSERT_EQUAL_TRANSFORM_TOL(kinDynDes.getWorldTransform("l_foot"),kinDynOpt.getWorldTransform("l_foot"),tolConstraints);
    ASSERT_EQUAL_TRANSFORM_TOL(kinDynDes.getWorldTransform("r_sole"),kinDynOpt.getWorldTransform("r_sole"),tolConstraints);
    ASSERT_EQUAL_VECTOR_TOL(kinDynDes.getCenterOfMassPosition(),
                            kinDynOpt.getCenterOfMassPosition(),tolTargets);

    return;
}

int main()
{
    // Improve repetability (at least in the same platform)
    srand(0);

    simpleChainIK(2,13,iDynTree::InverseKinematicsRotationParametrizationRollPitchYaw);

    // This is not working at the moment, there is some problem with quaternion constraints
    //simpleChainIK(10,iDynTree::InverseKinematicsRotationParametrizationQuaternion);

    simpleHumanoidWholeBodyIKConsistency(iDynTree::InverseKinematicsRotationParametrizationRollPitchYaw);
    simpleHumanoidWholeBodyIKCoMConsistency(iDynTree::InverseKinematicsRotationParametrizationRollPitchYaw, iDynTree::InverseKinematicsTreatTargetAsConstraintNone);
    simpleHumanoidWholeBodyIKCoMConsistency(iDynTree::InverseKinematicsRotationParametrizationRollPitchYaw, iDynTree::InverseKinematicsTreatTargetAsConstraintFull);

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h"

#include "chrome/browser/defaults.h"
#include "chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/sad_tab_helper.h"
#include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h"
#include "chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.h"
#include "chrome/browser/ui/views/sad_tab_view.h"
#include "components/web_modal/popup_manager.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/widget/widget.h"

#if defined(USE_AURA)
#include "chrome/browser/ui/views/link_disambiguation/link_disambiguation_popup.h"
#endif

ChromeWebContentsViewDelegateViews::ChromeWebContentsViewDelegateViews(
    content::WebContents* web_contents)
    : ContextMenuDelegate(web_contents),
      web_contents_(web_contents) {
  last_focused_view_storage_id_ =
      views::ViewStorage::GetInstance()->CreateStorageID();
}

ChromeWebContentsViewDelegateViews::~ChromeWebContentsViewDelegateViews() {
  // Makes sure to remove any stored view we may still have in the ViewStorage.
  //
  // It is possible the view went away before us, so we only do this if the
  // view is registered.
  views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
  if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
    view_storage->RemoveView(last_focused_view_storage_id_);
}

gfx::NativeWindow ChromeWebContentsViewDelegateViews::GetNativeWindow() {
  Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
  return browser ? browser->window()->GetNativeWindow() : nullptr;
}

content::WebDragDestDelegate*
    ChromeWebContentsViewDelegateViews::GetDragDestDelegate() {
  // We install a chrome specific handler to intercept bookmark drags for the
  // bookmark manager/extension API.
  bookmark_handler_.reset(new WebDragBookmarkHandlerAura);
  return bookmark_handler_.get();
}

bool ChromeWebContentsViewDelegateViews::Focus() {
  SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
  if (sad_tab_helper) {
    SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
    if (sad_tab) {
      sad_tab->RequestFocus();
      return true;
    }
  }

  web_modal::PopupManager* popup_manager =
      web_modal::PopupManager::FromWebContents(web_contents_);
  if (popup_manager)
    popup_manager->WasFocused(web_contents_);

  return false;
}

void ChromeWebContentsViewDelegateViews::TakeFocus(bool reverse) {
  views::FocusManager* focus_manager = GetFocusManager();
  if (focus_manager)
    focus_manager->AdvanceFocus(reverse);
}

void ChromeWebContentsViewDelegateViews::StoreFocus() {
  views::ViewStorage* view_storage = views::ViewStorage::GetInstance();

  if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
    view_storage->RemoveView(last_focused_view_storage_id_);

  if (!GetFocusManager())
    return;
  views::View* focused_view = GetFocusManager()->GetFocusedView();
  if (focused_view)
    view_storage->StoreView(last_focused_view_storage_id_, focused_view);
}

void ChromeWebContentsViewDelegateViews::RestoreFocus() {
  views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
  views::View* last_focused_view =
      view_storage->RetrieveView(last_focused_view_storage_id_);

  if (!last_focused_view) {
    SetInitialFocus();
  } else {
    if (last_focused_view->IsFocusable() &&
        GetFocusManager()->ContainsView(last_focused_view)) {
      last_focused_view->RequestFocus();
    } else {
      // The focused view may not belong to the same window hierarchy (e.g.
      // if the location bar was focused and the tab is dragged out), or it may
      // no longer be focusable (e.g. if the location bar was focused and then
      // we switched to fullscreen mode).  In that case we default to the
      // default focus.
      SetInitialFocus();
    }
    view_storage->RemoveView(last_focused_view_storage_id_);
  }
}

scoped_ptr<RenderViewContextMenuBase>
ChromeWebContentsViewDelegateViews::BuildMenu(
    content::WebContents* web_contents,
    const content::ContextMenuParams& params) {
  scoped_ptr<RenderViewContextMenuBase> menu;
  content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame();
  // If the frame tree does not have a focused frame at this point, do not
  // bother creating RenderViewContextMenuViews.
  // This happens if the frame has navigated to a different page before
  // ContextMenu message was received by the current RenderFrameHost.
  if (focused_frame) {
    menu.reset(RenderViewContextMenuViews::Create(focused_frame, params));
    menu->Init();
  }
  return menu.Pass();
}

void ChromeWebContentsViewDelegateViews::ShowMenu(
    scoped_ptr<RenderViewContextMenuBase> menu) {
  context_menu_ = menu.Pass();
  if (!context_menu_)
    return;

  context_menu_->Show();
}

void ChromeWebContentsViewDelegateViews::ShowContextMenu(
    content::RenderFrameHost* render_frame_host,
    const content::ContextMenuParams& params) {
  ShowMenu(
      BuildMenu(content::WebContents::FromRenderFrameHost(render_frame_host),
                params));
}

void ChromeWebContentsViewDelegateViews::ShowDisambiguationPopup(
    const gfx::Rect& target_rect,
    const SkBitmap& zoomed_bitmap,
    const gfx::NativeView content,
    const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
    const base::Callback<void(ui::MouseEvent*)>& mouse_cb) {
#if defined(USE_AURA)
  // If we are attempting to show a link disambiguation popup while already
  // showing one this means that the popup itself received an ambiguous touch.
  // Don't show another popup in this case.
  if (link_disambiguation_popup_) {
    link_disambiguation_popup_.reset();
    return;
  }

  link_disambiguation_popup_.reset(new LinkDisambiguationPopup);
  link_disambiguation_popup_->Show(
      views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView()),
      zoomed_bitmap,
      target_rect,
      content,
      gesture_cb,
      mouse_cb);
#endif
}

void ChromeWebContentsViewDelegateViews::HideDisambiguationPopup() {
  link_disambiguation_popup_.reset();
}

void ChromeWebContentsViewDelegateViews::SizeChanged(const gfx::Size& size) {
  SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
  if (!sad_tab_helper)
    return;
  SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
  if (sad_tab)
    sad_tab->GetWidget()->SetBounds(gfx::Rect(size));
}

aura::Window* ChromeWebContentsViewDelegateViews::GetActiveNativeView() {
  return web_contents_->GetFullscreenRenderWidgetHostView() ?
      web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() :
      web_contents_->GetNativeView();
}

views::Widget* ChromeWebContentsViewDelegateViews::GetTopLevelWidget() {
  return views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView());
}

views::FocusManager*
    ChromeWebContentsViewDelegateViews::GetFocusManager() {
  views::Widget* toplevel_widget = GetTopLevelWidget();
  return toplevel_widget ? toplevel_widget->GetFocusManager() : NULL;
}

void ChromeWebContentsViewDelegateViews::SetInitialFocus() {
  if (web_contents_->FocusLocationBarByDefault()) {
    if (web_contents_->GetDelegate())
      web_contents_->GetDelegate()->SetFocusToLocationBar(false);
  } else {
    web_contents_->Focus();
  }
}

namespace chrome {

content::WebContentsViewDelegate* CreateWebContentsViewDelegate(
    content::WebContents* web_contents) {
  return new ChromeWebContentsViewDelegateViews(web_contents);
}

}  // namespace chrome
<commit_msg>Remove some unncessary #include-s from ChromeWebContentsViewDelegateViews.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h"

#include "chrome/browser/defaults.h"
#include "chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/sad_tab_helper.h"
#include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h"
#include "chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.h"
#include "chrome/browser/ui/views/sad_tab_view.h"
#include "components/web_modal/popup_manager.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "ui/aura/window.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/widget/widget.h"

#if defined(USE_AURA)
#include "chrome/browser/ui/views/link_disambiguation/link_disambiguation_popup.h"
#endif

ChromeWebContentsViewDelegateViews::ChromeWebContentsViewDelegateViews(
    content::WebContents* web_contents)
    : ContextMenuDelegate(web_contents),
      web_contents_(web_contents) {
  last_focused_view_storage_id_ =
      views::ViewStorage::GetInstance()->CreateStorageID();
}

ChromeWebContentsViewDelegateViews::~ChromeWebContentsViewDelegateViews() {
  // Makes sure to remove any stored view we may still have in the ViewStorage.
  //
  // It is possible the view went away before us, so we only do this if the
  // view is registered.
  views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
  if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
    view_storage->RemoveView(last_focused_view_storage_id_);
}

gfx::NativeWindow ChromeWebContentsViewDelegateViews::GetNativeWindow() {
  Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
  return browser ? browser->window()->GetNativeWindow() : nullptr;
}

content::WebDragDestDelegate*
    ChromeWebContentsViewDelegateViews::GetDragDestDelegate() {
  // We install a chrome specific handler to intercept bookmark drags for the
  // bookmark manager/extension API.
  bookmark_handler_.reset(new WebDragBookmarkHandlerAura);
  return bookmark_handler_.get();
}

bool ChromeWebContentsViewDelegateViews::Focus() {
  SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
  if (sad_tab_helper) {
    SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
    if (sad_tab) {
      sad_tab->RequestFocus();
      return true;
    }
  }

  web_modal::PopupManager* popup_manager =
      web_modal::PopupManager::FromWebContents(web_contents_);
  if (popup_manager)
    popup_manager->WasFocused(web_contents_);

  return false;
}

void ChromeWebContentsViewDelegateViews::TakeFocus(bool reverse) {
  views::FocusManager* focus_manager = GetFocusManager();
  if (focus_manager)
    focus_manager->AdvanceFocus(reverse);
}

void ChromeWebContentsViewDelegateViews::StoreFocus() {
  views::ViewStorage* view_storage = views::ViewStorage::GetInstance();

  if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
    view_storage->RemoveView(last_focused_view_storage_id_);

  if (!GetFocusManager())
    return;
  views::View* focused_view = GetFocusManager()->GetFocusedView();
  if (focused_view)
    view_storage->StoreView(last_focused_view_storage_id_, focused_view);
}

void ChromeWebContentsViewDelegateViews::RestoreFocus() {
  views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
  views::View* last_focused_view =
      view_storage->RetrieveView(last_focused_view_storage_id_);

  if (!last_focused_view) {
    SetInitialFocus();
  } else {
    if (last_focused_view->IsFocusable() &&
        GetFocusManager()->ContainsView(last_focused_view)) {
      last_focused_view->RequestFocus();
    } else {
      // The focused view may not belong to the same window hierarchy (e.g.
      // if the location bar was focused and the tab is dragged out), or it may
      // no longer be focusable (e.g. if the location bar was focused and then
      // we switched to fullscreen mode).  In that case we default to the
      // default focus.
      SetInitialFocus();
    }
    view_storage->RemoveView(last_focused_view_storage_id_);
  }
}

scoped_ptr<RenderViewContextMenuBase>
ChromeWebContentsViewDelegateViews::BuildMenu(
    content::WebContents* web_contents,
    const content::ContextMenuParams& params) {
  scoped_ptr<RenderViewContextMenuBase> menu;
  content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame();
  // If the frame tree does not have a focused frame at this point, do not
  // bother creating RenderViewContextMenuViews.
  // This happens if the frame has navigated to a different page before
  // ContextMenu message was received by the current RenderFrameHost.
  if (focused_frame) {
    menu.reset(RenderViewContextMenuViews::Create(focused_frame, params));
    menu->Init();
  }
  return menu.Pass();
}

void ChromeWebContentsViewDelegateViews::ShowMenu(
    scoped_ptr<RenderViewContextMenuBase> menu) {
  context_menu_ = menu.Pass();
  if (!context_menu_)
    return;

  context_menu_->Show();
}

void ChromeWebContentsViewDelegateViews::ShowContextMenu(
    content::RenderFrameHost* render_frame_host,
    const content::ContextMenuParams& params) {
  ShowMenu(
      BuildMenu(content::WebContents::FromRenderFrameHost(render_frame_host),
                params));
}

void ChromeWebContentsViewDelegateViews::ShowDisambiguationPopup(
    const gfx::Rect& target_rect,
    const SkBitmap& zoomed_bitmap,
    const gfx::NativeView content,
    const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
    const base::Callback<void(ui::MouseEvent*)>& mouse_cb) {
#if defined(USE_AURA)
  // If we are attempting to show a link disambiguation popup while already
  // showing one this means that the popup itself received an ambiguous touch.
  // Don't show another popup in this case.
  if (link_disambiguation_popup_) {
    link_disambiguation_popup_.reset();
    return;
  }

  link_disambiguation_popup_.reset(new LinkDisambiguationPopup);
  link_disambiguation_popup_->Show(
      views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView()),
      zoomed_bitmap,
      target_rect,
      content,
      gesture_cb,
      mouse_cb);
#endif
}

void ChromeWebContentsViewDelegateViews::HideDisambiguationPopup() {
  link_disambiguation_popup_.reset();
}

void ChromeWebContentsViewDelegateViews::SizeChanged(const gfx::Size& size) {
  SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
  if (!sad_tab_helper)
    return;
  SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
  if (sad_tab)
    sad_tab->GetWidget()->SetBounds(gfx::Rect(size));
}

aura::Window* ChromeWebContentsViewDelegateViews::GetActiveNativeView() {
  return web_contents_->GetFullscreenRenderWidgetHostView() ?
      web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() :
      web_contents_->GetNativeView();
}

views::Widget* ChromeWebContentsViewDelegateViews::GetTopLevelWidget() {
  return views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView());
}

views::FocusManager*
    ChromeWebContentsViewDelegateViews::GetFocusManager() {
  views::Widget* toplevel_widget = GetTopLevelWidget();
  return toplevel_widget ? toplevel_widget->GetFocusManager() : NULL;
}

void ChromeWebContentsViewDelegateViews::SetInitialFocus() {
  if (web_contents_->FocusLocationBarByDefault()) {
    if (web_contents_->GetDelegate())
      web_contents_->GetDelegate()->SetFocusToLocationBar(false);
  } else {
    web_contents_->Focus();
  }
}

namespace chrome {

content::WebContentsViewDelegate* CreateWebContentsViewDelegate(
    content::WebContents* web_contents) {
  return new ChromeWebContentsViewDelegateViews(web_contents);
}

}  // namespace chrome
<|endoftext|>


<commit_before>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);

}<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);
	m_pShape->SetBody(NULL);
	m_pShape->SetBody(m_pDummy);

	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_pShape->SetRestitution(0.0f);
	m_pShape->SetCollisionMask(2);

}<|endoftext|>


<commit_before>#include "qjsonobjectconverter_p.h"
#include "qjsonserializerexception.h"
#include "qjsonserializer_p.h"

#include <QtCore/QPointer>
#include <QtCore/QSharedPointer>
#include <QtCore/QRegularExpression>
#include <QtCore/QDebug>

const QRegularExpression QJsonObjectConverter::sharedTypeRegex(QStringLiteral(R"__(^QSharedPointer<\s*(.*?)\s*>$)__"));
const QRegularExpression QJsonObjectConverter::trackingTypeRegex(QStringLiteral(R"__(^QPointer<\s*(.*?)\s*>$)__"));

bool QJsonObjectConverter::canConvert(int metaTypeId) const
{
	auto flags = QMetaType::typeFlags(metaTypeId);
	return flags.testFlag(QMetaType::PointerToQObject) ||
			flags.testFlag(QMetaType::SharedPointerToQObject) ||//weak ptr cannot be constructed
			flags.testFlag(QMetaType::TrackingPointerToQObject);
}

QList<QJsonValue::Type> QJsonObjectConverter::jsonTypes() const
{
	return {
		QJsonValue::Object,
		QJsonValue::Null
	};
}

QJsonValue QJsonObjectConverter::serialize(int propertyType, const QVariant &value, const QJsonTypeConverter::SerializationHelper *helper) const
{
	QObject *object = nullptr;
	auto flags = QMetaType::typeFlags(propertyType);
	if(flags.testFlag(QMetaType::PointerToQObject))
	  object = extract<QObject*>(value);
	else if(flags.testFlag(QMetaType::SharedPointerToQObject))
	  object = extract<QSharedPointer<QObject>>(value).data();
	else if(flags.testFlag(QMetaType::TrackingPointerToQObject))
	  object = extract<QPointer<QObject>>(value).data();
	else
	  Q_UNREACHABLE();

	if(object) {
		//get the metaobject, based on polymorphism
		const QMetaObject *meta = nullptr;
		auto poly = (QJsonSerializer::Polymorphing)helper->getProperty("polymorphic").toInt();
		auto isPoly = false;
		switch (poly) {
		case QJsonSerializer::Disabled:
			isPoly = false;
			break;
		case QJsonSerializer::Enabled:
			isPoly = polyMetaObject(object);
			break;
		case QJsonSerializer::Forced:
			isPoly = true;
			break;
		default:
			Q_UNREACHABLE();
			break;
		}

		QJsonObject jsonObject;

		if(isPoly) {
			meta = object->metaObject();
			//first: pass the class name
			jsonObject[QStringLiteral("@class")] = QString::fromUtf8(meta->className());
		} else
			meta = getMetaObject(propertyType);

		//go through all properties and try to serialize them
		auto keepObjectName = helper->getProperty("keepObjectName").toBool();
		auto i = QObject::staticMetaObject.indexOfProperty("objectName");
		if(!keepObjectName)
		   i++;
		for(; i < meta->propertyCount(); i++) {
			auto property = meta->property(i);
			if(property.isStored())
				jsonObject[QString::fromUtf8(property.name())] = helper->serializeSubtype(property, property.read(object));
		}

		return jsonObject;
	}
	else
		return QJsonValue();
}

QVariant QJsonObjectConverter::deserialize(int propertyType, const QJsonValue &value, QObject *parent, const QJsonTypeConverter::SerializationHelper *helper) const
{
	if(value.isNull())
		return toVariant(nullptr, QMetaType::typeFlags(propertyType));

	auto validationFlags = helper->getProperty("validationFlags").value<QJsonSerializer::ValidationFlags>();
	auto keepObjectName = helper->getProperty("keepObjectName").toBool();
	auto metaObject = getMetaObject(propertyType);
	if(!metaObject)
		throw QJsonDeserializationException(QByteArray("Unable to get metaobject for type ") + QMetaType::typeName(propertyType));

	//try to construct the object
	auto object = metaObject->newInstance(Q_ARG(QObject*, parent));
	if(!object) {
		throw QJsonDeserializationException(QByteArray("Failed to construct object of type ") +
											metaObject->className() +
											QByteArray(" (Does the constructor \"Q_INVOKABLE class(QObject*);\" exist?)"));
	}

	//collect required properties, if set
	QSet<QByteArray> reqProps;
	if(validationFlags.testFlag(QJsonSerializer::AllProperties)) {
		auto i = QObject::staticMetaObject.indexOfProperty("objectName");
		if(!keepObjectName)
		   i++;
		for(; i < metaObject->propertyCount(); i++) {
			auto property = metaObject->property(i);
			if(property.isStored())
				reqProps.insert(property.name());
		}
	}

	//now deserialize all json properties
	auto jsonObject = value.toObject();
	for(auto it = jsonObject.constBegin(); it != jsonObject.constEnd(); it++) {
		auto propIndex = metaObject->indexOfProperty(qUtf8Printable(it.key()));
		QVariant value;
		if(propIndex != -1) {
			auto property = metaObject->property(propIndex);
			value = helper->deserializeSubtype(property, it.value(), object);
			reqProps.remove(property.name());
		} else if(validationFlags.testFlag(QJsonSerializer::NoExtraProperties)) {
			throw QJsonDeserializationException("Found extra property " +
												it.key().toUtf8() +
												" but extra properties are not allowed");
		} else
			value = helper->deserializeSubtype(QMetaType::UnknownType, it.value(), object);
		object->setProperty(qUtf8Printable(it.key()), value);
	}

	//make shure all required properties have been read
	if(validationFlags.testFlag(QJsonSerializer::AllProperties) && !reqProps.isEmpty()) {
		throw QJsonDeserializationException(QByteArray("Not all properties for ") +
											metaObject->className() +
											QByteArray(" are present in the json object Missing properties: ") +
											reqProps.toList().join(", "));
	}

	return toVariant(object, QMetaType::typeFlags(propertyType));
}

const QMetaObject *QJsonObjectConverter::getMetaObject(int typeId)
{
	auto flags = QMetaType::typeFlags(typeId);
	if(flags.testFlag(QMetaType::PointerToQObject))
		return QMetaType::metaObjectForType(typeId);
	else {
		QRegularExpression regex;
		if(flags.testFlag(QMetaType::SharedPointerToQObject))
			regex = sharedTypeRegex;
		else if(flags.testFlag(QMetaType::TrackingPointerToQObject))
			regex = trackingTypeRegex;
		else {
			Q_UNREACHABLE();
			return nullptr;
		}

		//extract template type, and if found, add the pointer star and find the meta type
		auto match = regex.match(QString::fromUtf8(QMetaType::typeName(typeId)));
		if(match.hasMatch()) {
			auto type = QMetaType::type(match.captured(1).toUtf8().trimmed() + "*");
			return QMetaType::metaObjectForType(type);
		} else
			return nullptr;
	}
}

template<typename T>
T QJsonObjectConverter::extract(QVariant variant)
{
  auto id = qMetaTypeId<T>();
  if(variant.canConvert(id) && variant.convert(id))
	return variant.value<T>();
  else
	throw QJsonSerializationException(QByteArray("unable to get QObject pointer from type ") + QMetaType::typeName(id));
}

QVariant QJsonObjectConverter::toVariant(QObject *object, QMetaType::TypeFlags flags)
{
	if(flags.testFlag(QMetaType::PointerToQObject))
		return QVariant::fromValue(object);
	else if(flags.testFlag(QMetaType::SharedPointerToQObject)) {
		//remove parent, as shared pointers and object tree exclude each other
		if(object)
			object->setParent(nullptr);
		return QVariant::fromValue(QSharedPointer<QObject>(object));
	} else if(flags.testFlag(QMetaType::TrackingPointerToQObject))
		return QVariant::fromValue<QPointer<QObject>>(object);
	else {
		Q_UNREACHABLE();
		return QVariant();
	}
}

bool QJsonObjectConverter::polyMetaObject(QObject *object)
{
	auto meta = object->metaObject();

	//check the internal property
	if(object->dynamicPropertyNames().contains("__qt_json_serializer_polymorphic")) {
		auto polyProp = object->property("__qt_json_serializer_polymorphic").toBool();
		return polyProp;
	}

	//check the class info
	auto polyIndex = meta->indexOfClassInfo("polymorphic");
	if(polyIndex != -1) {
		auto info = meta->classInfo(polyIndex);
		if(info.value() == QByteArray("true"))
			return true;// use the object
		else if(info.value() == QByteArray("false"))
			return false;// use the class
		else
			qWarning() << "Invalid value for polymorphic classinfo on object type" << meta->className() << "ignored";
	}

	//default: the class
	return false;// use the class
}
<commit_msg>added poly deserialize<commit_after>#include "qjsonobjectconverter_p.h"
#include "qjsonserializerexception.h"
#include "qjsonserializer_p.h"

#include <QtCore/QPointer>
#include <QtCore/QSharedPointer>
#include <QtCore/QRegularExpression>
#include <QtCore/QDebug>

const QRegularExpression QJsonObjectConverter::sharedTypeRegex(QStringLiteral(R"__(^QSharedPointer<\s*(.*?)\s*>$)__"));
const QRegularExpression QJsonObjectConverter::trackingTypeRegex(QStringLiteral(R"__(^QPointer<\s*(.*?)\s*>$)__"));

bool QJsonObjectConverter::canConvert(int metaTypeId) const
{
	auto flags = QMetaType::typeFlags(metaTypeId);
	return flags.testFlag(QMetaType::PointerToQObject) ||
			flags.testFlag(QMetaType::SharedPointerToQObject) ||//weak ptr cannot be constructed
			flags.testFlag(QMetaType::TrackingPointerToQObject);
}

QList<QJsonValue::Type> QJsonObjectConverter::jsonTypes() const
{
	return {
		QJsonValue::Object,
		QJsonValue::Null
	};
}

QJsonValue QJsonObjectConverter::serialize(int propertyType, const QVariant &value, const QJsonTypeConverter::SerializationHelper *helper) const
{
	QObject *object = nullptr;
	auto flags = QMetaType::typeFlags(propertyType);
	if(flags.testFlag(QMetaType::PointerToQObject))
	  object = extract<QObject*>(value);
	else if(flags.testFlag(QMetaType::SharedPointerToQObject))
	  object = extract<QSharedPointer<QObject>>(value).data();
	else if(flags.testFlag(QMetaType::TrackingPointerToQObject))
	  object = extract<QPointer<QObject>>(value).data();
	else
	  Q_UNREACHABLE();

	if(object) {
		//get the metaobject, based on polymorphism
		const QMetaObject *meta = nullptr;
		auto poly = (QJsonSerializer::Polymorphing)helper->getProperty("polymorphic").toInt();
		auto isPoly = false;
		switch (poly) {
		case QJsonSerializer::Disabled:
			isPoly = false;
			break;
		case QJsonSerializer::Enabled:
			isPoly = polyMetaObject(object);
			break;
		case QJsonSerializer::Forced:
			isPoly = true;
			break;
		default:
			Q_UNREACHABLE();
			break;
		}

		QJsonObject jsonObject;

		if(isPoly) {
			meta = object->metaObject();
			//first: pass the class name
			jsonObject[QStringLiteral("@class")] = QString::fromUtf8(meta->className());
		} else
			meta = getMetaObject(propertyType);

		//go through all properties and try to serialize them
		auto keepObjectName = helper->getProperty("keepObjectName").toBool();
		auto i = QObject::staticMetaObject.indexOfProperty("objectName");
		if(!keepObjectName)
		   i++;
		for(; i < meta->propertyCount(); i++) {
			auto property = meta->property(i);
			if(property.isStored())
				jsonObject[QString::fromUtf8(property.name())] = helper->serializeSubtype(property, property.read(object));
		}

		return jsonObject;
	}
	else
		return QJsonValue();
}

QVariant QJsonObjectConverter::deserialize(int propertyType, const QJsonValue &value, QObject *parent, const QJsonTypeConverter::SerializationHelper *helper) const
{
	if(value.isNull())
		return toVariant(nullptr, QMetaType::typeFlags(propertyType));

	auto validationFlags = helper->getProperty("validationFlags").value<QJsonSerializer::ValidationFlags>();
	auto keepObjectName = helper->getProperty("keepObjectName").toBool();
	auto poly = (QJsonSerializer::Polymorphing)helper->getProperty("polymorphic").toInt();

	auto metaObject = getMetaObject(propertyType);
	if(!metaObject)
		throw QJsonDeserializationException(QByteArray("Unable to get metaobject for type ") + QMetaType::typeName(propertyType));

	//try to get the polymorphic metatype (if allowed)
	auto jsonObject = value.toObject();
	if(poly != QJsonSerializer::Disabled) {
		if(jsonObject.contains(QStringLiteral("@class"))) {
			auto classField = jsonObject[QStringLiteral("@class")].toString().toUtf8();
			auto typeId = QMetaType::type(classField.constData());
			auto nMeta = QMetaType::metaObjectForType(typeId);
			if(!nMeta)
				throw QJsonDeserializationException("Unable to find class requested from json \"@class\" property: " + classField);
			if(!nMeta->inherits(metaObject)) {
				throw QJsonDeserializationException("Requested class from \"@class\" field, " +
													classField +
													QByteArray(", does not inhert the property type ") +
													QMetaType::typeName(propertyType));
			}
			metaObject = nMeta;
		} else if(poly == QJsonSerializer::Forced)
			throw QJsonDeserializationException("Json does not contain the \"@class\" field, but forced polymorphism requires it");
	}

	//try to construct the object
	auto object = metaObject->newInstance(Q_ARG(QObject*, parent));
	if(!object) {
		throw QJsonDeserializationException(QByteArray("Failed to construct object of type ") +
											metaObject->className() +
											QByteArray(" (Does the constructor \"Q_INVOKABLE class(QObject*);\" exist?)"));
	}

	//collect required properties, if set
	QSet<QByteArray> reqProps;
	if(validationFlags.testFlag(QJsonSerializer::AllProperties)) {
		auto i = QObject::staticMetaObject.indexOfProperty("objectName");
		if(!keepObjectName)
		   i++;
		for(; i < metaObject->propertyCount(); i++) {
			auto property = metaObject->property(i);
			if(property.isStored())
				reqProps.insert(property.name());
		}
	}

	//now deserialize all json properties
	for(auto it = jsonObject.constBegin(); it != jsonObject.constEnd(); it++) {
		auto propIndex = metaObject->indexOfProperty(qUtf8Printable(it.key()));
		QVariant value;
		if(propIndex != -1) {
			auto property = metaObject->property(propIndex);
			value = helper->deserializeSubtype(property, it.value(), object);
			reqProps.remove(property.name());
		} else if(validationFlags.testFlag(QJsonSerializer::NoExtraProperties)) {
			throw QJsonDeserializationException("Found extra property " +
												it.key().toUtf8() +
												" but extra properties are not allowed");
		} else
			value = helper->deserializeSubtype(QMetaType::UnknownType, it.value(), object);
		object->setProperty(qUtf8Printable(it.key()), value);
	}

	//make shure all required properties have been read
	if(validationFlags.testFlag(QJsonSerializer::AllProperties) && !reqProps.isEmpty()) {
		throw QJsonDeserializationException(QByteArray("Not all properties for ") +
											metaObject->className() +
											QByteArray(" are present in the json object Missing properties: ") +
											reqProps.toList().join(", "));
	}

	return toVariant(object, QMetaType::typeFlags(propertyType));
}

const QMetaObject *QJsonObjectConverter::getMetaObject(int typeId)
{
	auto flags = QMetaType::typeFlags(typeId);
	if(flags.testFlag(QMetaType::PointerToQObject))
		return QMetaType::metaObjectForType(typeId);
	else {
		QRegularExpression regex;
		if(flags.testFlag(QMetaType::SharedPointerToQObject))
			regex = sharedTypeRegex;
		else if(flags.testFlag(QMetaType::TrackingPointerToQObject))
			regex = trackingTypeRegex;
		else {
			Q_UNREACHABLE();
			return nullptr;
		}

		//extract template type, and if found, add the pointer star and find the meta type
		auto match = regex.match(QString::fromUtf8(QMetaType::typeName(typeId)));
		if(match.hasMatch()) {
			auto type = QMetaType::type(match.captured(1).toUtf8().trimmed() + "*");
			return QMetaType::metaObjectForType(type);
		} else
			return nullptr;
	}
}

template<typename T>
T QJsonObjectConverter::extract(QVariant variant)
{
  auto id = qMetaTypeId<T>();
  if(variant.canConvert(id) && variant.convert(id))
	return variant.value<T>();
  else
	throw QJsonSerializationException(QByteArray("unable to get QObject pointer from type ") + QMetaType::typeName(id));
}

QVariant QJsonObjectConverter::toVariant(QObject *object, QMetaType::TypeFlags flags)
{
	if(flags.testFlag(QMetaType::PointerToQObject))
		return QVariant::fromValue(object);
	else if(flags.testFlag(QMetaType::SharedPointerToQObject)) {
		//remove parent, as shared pointers and object tree exclude each other
		if(object)
			object->setParent(nullptr);
		return QVariant::fromValue(QSharedPointer<QObject>(object));
	} else if(flags.testFlag(QMetaType::TrackingPointerToQObject))
		return QVariant::fromValue<QPointer<QObject>>(object);
	else {
		Q_UNREACHABLE();
		return QVariant();
	}
}

bool QJsonObjectConverter::polyMetaObject(QObject *object)
{
	auto meta = object->metaObject();

	//check the internal property
	if(object->dynamicPropertyNames().contains("__qt_json_serializer_polymorphic")) {
		auto polyProp = object->property("__qt_json_serializer_polymorphic").toBool();
		return polyProp;
	}

	//check the class info
	auto polyIndex = meta->indexOfClassInfo("polymorphic");
	if(polyIndex != -1) {
		auto info = meta->classInfo(polyIndex);
		if(info.value() == QByteArray("true"))
			return true;// use the object
		else if(info.value() == QByteArray("false"))
			return false;// use the class
		else
			qWarning() << "Invalid value for polymorphic classinfo on object type" << meta->className() << "ignored";
	}

	//default: the class
	return false;// use the class
}
<|endoftext|>


<commit_before>#ifndef DUNE_STUFF_COMMON_PARAMETER_TREE_HH
#define DUNE_STUFF_COMMON_PARAMETER_TREE_HH

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#else
  #include "config.h"
#endif // ifdef HAVE_CMAKE_CONFIG

#include <cstring>
#include <sstream>
#include <vector>

#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

#if HAVE_EIGEN
  #include <Eigen/Core>
#endif // HAVE_EIGEN

#include <dune/common/exceptions.hh>
#include <dune/common/parametertreeparser.hh>
#include <dune/common/dynvector.hh>

#include <dune/stuff/common/string.hh>
#include <dune/stuff/common/color.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/aliases.hh>

namespace Dune {
namespace Stuff {
namespace Common {

//! ParameterTree extension for nicer output
//! \todo TODO The report method should go into dune-common
class ExtendedParameterTree
  : public Dune::ParameterTree {

  typedef Dune::ParameterTree BaseType;

public:
  ExtendedParameterTree();
  ExtendedParameterTree(const std::string filename);
  ExtendedParameterTree(int argc, char** argv, std::string filename);
  ExtendedParameterTree(const Dune::ParameterTree& other);

  ExtendedParameterTree& operator=(const Dune::ParameterTree& other);

  /**
   *  \brief adds another Dune::ParameterTree
   */
  void add(const Dune::ParameterTree& _other, const std::string _subName = "");
  ExtendedParameterTree sub(const std::string& _sub) const;

  void report(std::ostream& stream = std::cout, const std::string& prefix = "") const;
  void reportNicely(std::ostream& stream = std::cout) const;
  std::string reportString(const std::string& prefix = "") const;

  std::string get(const std::string& key, const char* defaultValue) const
  {
    return this->get< std::string >(key, std::string(defaultValue));
  }

  template< typename T >
  T get(const std::string& key, const T& defaultValue) const
  {
    if (!BaseType::hasKey(key)) {
      DSC::Logger().debug() << DSC::colorString("WARNING:") << " missing key '" << key << "' is replaced by given default value!" << std::endl;
    }
    return BaseType::get< T >(key, defaultValue);
  }

  template< class T >
  T get(const std::string& key) const
  {
    if (!BaseType::hasKey(key))
      DUNE_THROW(Dune::RangeError,
                 "\n" << Dune::Stuff::Common::colorStringRed("ERROR:") << " key '" << key << "' missing  in the following Dune::ParameterTree:\n" << reportString("  "));
    return BaseType::get< T >(key);
  }

  bool hasVector(const std::string& key) const;

  template< class T >
  Dune::DynamicVector< T > getDynVector(const std::string& key, const T& def, const size_t minSize) const
  {
    const std::vector< T > vector = getVector< T >(key, def, minSize);
    Dune::DynamicVector< T > ret(vector.size());
    for (size_t ii = 0; ii < vector.size(); ++ii)
      ret[ii] = vector[ii];
    return ret;
  }

  template< class T >
  std::vector< T > getVector(const std::string& key, const T& def, const unsigned int minSize) const
  {
    if (!hasKey(key)) {
      DSC::Logger().debug() << DSC::colorString("WARNING:") << " missing key '" << key << "' is replaced by given default value!" << std::endl;
      return std::vector< T >(minSize, def);
    } else {
      const std::string str = BaseType::get(key, "meaningless_default_value");
      if (str.empty()) {
        if (minSize > 0) {
          DSC::Logger().debug() << DSC::colorString("WARNING:") << " vector '" << key << "' was too small (0) and has been enlarged to size " << minSize << "!" << std::endl;
        }
        return std::vector< T >(minSize, def);
      } else if (str.size() < 3) {
        std::vector< T > ret;
        ret.push_back(DSC::fromString< T >(str));
        if (ret.size() < minSize) {
          DSC::Logger().debug() << DSC::colorString("WARNING:") << " vector '" << key << "' was too small (" << ret.size() << ") and has been enlarged to size " << minSize << "!" << std::endl;
          for (auto i = ret.size(); i < minSize; ++i)
            ret.push_back(def);
        }
        return ret;
      } else {
        // the dune parametertree strips any leading and trailing whitespace
        // so we can be sure that the first and last have to be the brackets [] if this is a vector
        std::vector< T > ret;
        if (str.substr(0, 1) == "["
            && str.substr(str.size() - 1, 1) == "]") {
          std::vector< std::string > tokens;
          if (str.size() > 2)
            tokens = DSC::tokenize< std::string >(str.substr(1, str.size() - 2), ";");
          for (unsigned int i = 0; i < tokens.size(); ++i)
            ret.push_back(DSC::fromString< T >(boost::algorithm::trim_copy(tokens[i])));
          for (auto i = ret.size(); i < minSize; ++i)
            ret.push_back(def);
        } else if (str.substr(0, 1) == "["
                   || str.substr(str.size() - 1, 1) == "]") {
            DUNE_THROW(Dune::RangeError, "Vectors have to be of the form '[entry_0; entry_1; ... ]'!");
        } else {
          ret = std::vector< T >(minSize, DSC::fromString< T >(boost::algorithm::trim_copy(str)));
        }
        return ret;
      }
    }
  } // std::vector< T > getVector(const std::string& key, const T def) const

  template< class T >
  Dune::DynamicVector< T > getDynVector(const std::string& _key, const size_t minSize) const
  {
    const std::vector< T > vector = getVector< T >(_key, minSize);
    Dune::DynamicVector< T > ret(vector.size());
    for (size_t ii = 0; ii < vector.size(); ++ii)
      ret[ii] = vector[ii];
    return ret;
  }

  template< class T >
  std::vector< T > getVector(const std::string& key, const unsigned int minSize) const
  {
    if (!hasKey(key)) {
      DUNE_THROW(Dune::RangeError,
                 "\n" << DSC::colorStringRed("ERROR:")
                 << " key '" << key << "' missing  in the following Dune::ParameterTree:\n" << reportString("  "));
    } else {
      std::vector< T > ret;
      const std::string str = BaseType::get< std::string >(key, "meaningless_default_value");
      // the dune parametertree strips any leading and trailing whitespace
      // so we can be sure that the first and last have to be the brackets [] if this is a vector
      if (str.substr(0, 1) == "[" && str.substr(str.size() - 1, 1) == "]") {
        const std::vector< std::string > tokens = DSC::tokenize< std::string >(str.substr(1, str.size() - 2), ";");
        for (unsigned int i = 0; i < tokens.size(); ++i)
          ret.push_back(DSC::fromString< T >(boost::algorithm::trim_copy(tokens[i])));
      } else if (minSize == 1)
        ret.push_back(DSC::fromString< T >(str));
      else
          DUNE_THROW(Dune::RangeError, "Vectors have to be of the form '[entry_0; entry_1; ... ]'!");
      if (ret.size() < minSize)
        DUNE_THROW(Dune::RangeError,
                   "\n" << DSC::colorStringRed("ERROR:")
                   << " vector '" << key
                   << "' too short (is " << ret.size() << ", should be at least " << minSize
                   << ") in the following Dune::ParameterTree :\n" << reportString("  "));
      return ret;
    }
  } // std::vector< T > getVector(const std::string& key, const T def) const

#if HAVE_EIGEN
  template< class T >
  Eigen::Matrix< T, Eigen::Dynamic, 1 > getEigenVector(const std::string& key,
                                                       const T& def,
                                                       const unsigned int minSize) const
  {
    // get correspongin vector
    std::vector< T > vec = getVector< T >(key, def, minSize);
    // create eigen vector and return
    Eigen::Matrix< T, Eigen::Dynamic, 1 > ret(vec.size());
    for (unsigned int i = 0; i < vec.size(); ++i)
      ret(i) = vec[i];
    return ret;
  }

  template< class T >
  Eigen::Matrix< T, Eigen::Dynamic, 1 > getEigenVector(const std::string& key, const unsigned int minSize) const
  {
    // get correspongin vector
    std::vector< T > vec = getVector< T >(key, minSize);
    // create eigen vector and return
    Eigen::Matrix< T, Eigen::Dynamic, 1 > ret(vec.size());
    for (unsigned int i = 0; i < vec.size(); ++i)
      ret(i) = vec[i];
    return ret;
  }
#endif // HAVE_EIGEN

  void assertKey(const std::string& key) const;
  void assertSub(const std::string& _sub) const;

  /**
    \brief      Fills a Dune::ParameterTree given a parameter file or command line arguments.
    \param[in]  argc
                From \c main()
    \param[in]  argv
                From \c main()
    \return     The Dune::ParameterTree that is to be filled.
    **/
  static ParameterTree init(int argc, char** argv, std::string filename);
  static ParameterTree init(const std::string filename);

private:
  void reportAsSub(std::ostream& stream, const std::string& prefix, const std::string& subPath) const;
  std::string findCommonPrefix(const BaseType& sub, const std::string previousPrefix = "") const;
  void reportFlatly(const BaseType& sub, const std::string& prefix = "", std::ostream& stream = std::cout) const;
}; // class ExtendedParameterTree

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_PARAMETER_TREE_HH

/** Copyright (c) 2012, Rene Milk, Felix Albrecht
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, this
   *    list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * The views and conclusions contained in the software and documentation are those
   * of the authors and should not be interpreted as representing official policies,
   * either expressed or implied, of the FreeBSD Project.
   **/
<commit_msg>[dune.stuff.common.parameter] fixed typo<commit_after>#ifndef DUNE_STUFF_COMMON_PARAMETER_TREE_HH
#define DUNE_STUFF_COMMON_PARAMETER_TREE_HH

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#else
  #include "config.h"
#endif // ifdef HAVE_CMAKE_CONFIG

#include <cstring>
#include <sstream>
#include <vector>

#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

#if HAVE_EIGEN
  #include <Eigen/Core>
#endif // HAVE_EIGEN

#include <dune/common/exceptions.hh>
#include <dune/common/parametertreeparser.hh>
#include <dune/common/dynvector.hh>

#include <dune/stuff/common/string.hh>
#include <dune/stuff/common/color.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/aliases.hh>

namespace Dune {
namespace Stuff {
namespace Common {

//! ParameterTree extension for nicer output
//! \todo TODO The report method should go into dune-common
class ExtendedParameterTree
  : public Dune::ParameterTree {

  typedef Dune::ParameterTree BaseType;

public:
  ExtendedParameterTree();
  ExtendedParameterTree(const std::string filename);
  ExtendedParameterTree(int argc, char** argv, std::string filename);
  ExtendedParameterTree(const Dune::ParameterTree& other);

  ExtendedParameterTree& operator=(const Dune::ParameterTree& other);

  /**
   *  \brief adds another Dune::ParameterTree
   */
  void add(const Dune::ParameterTree& _other, const std::string _subName = "");
  ExtendedParameterTree sub(const std::string& _sub) const;

  void report(std::ostream& stream = std::cout, const std::string& prefix = "") const;
  void reportNicely(std::ostream& stream = std::cout) const;
  std::string reportString(const std::string& prefix = "") const;

  std::string get(const std::string& key, const char* defaultValue) const
  {
    return this->get< std::string >(key, std::string(defaultValue));
  }

  template< typename T >
  T get(const std::string& key, const T& defaultValue) const
  {
    if (!BaseType::hasKey(key)) {
      DSC::Logger().debug() << DSC::colorString("WARNING:") << " missing key '" << key << "' is replaced by given default value!" << std::endl;
    }
    return BaseType::get< T >(key, defaultValue);
  }

  template< class T >
  T get(const std::string& key) const
  {
    if (!BaseType::hasKey(key))
      DUNE_THROW(Dune::RangeError,
                 "\n" << Dune::Stuff::Common::colorStringRed("ERROR:") << " key '" << key << "' missing  in the following Dune::ParameterTree:\n" << reportString("  "));
    return BaseType::get< T >(key);
  }

  bool hasVector(const std::string& key) const;

  template< class T >
  Dune::DynamicVector< T > getDynVector(const std::string& key, const T& def, const size_t minSize) const
  {
    const std::vector< T > vector = getVector< T >(key, def, minSize);
    Dune::DynamicVector< T > ret(vector.size());
    for (size_t ii = 0; ii < vector.size(); ++ii)
      ret[ii] = vector[ii];
    return ret;
  }

  template< class T >
  std::vector< T > getVector(const std::string& key, const T& def, const unsigned int minSize) const
  {
    if (!hasKey(key)) {
      DSC::Logger().debug() << DSC::colorString("WARNING:") << " missing key '" << key << "' is replaced by given default value!" << std::endl;
      return std::vector< T >(minSize, def);
    } else {
      const std::string str = BaseType::get(key, "meaningless_default_value");
      if (str.empty()) {
        if (minSize > 0) {
          DSC::Logger().debug() << DSC::colorString("WARNING:") << " vector '" << key << "' was too small (0) and has been enlarged to size " << minSize << "!" << std::endl;
        }
        return std::vector< T >(minSize, def);
      } else if (str.size() < 3) {
        std::vector< T > ret;
        ret.push_back(DSC::fromString< T >(str));
        if (ret.size() < minSize) {
          DSC::Logger().debug() << DSC::colorString("WARNING:") << " vector '" << key << "' was too small (" << ret.size() << ") and has been enlarged to size " << minSize << "!" << std::endl;
          for (auto i = ret.size(); i < minSize; ++i)
            ret.push_back(def);
        }
        return ret;
      } else {
        // the dune parametertree strips any leading and trailing whitespace
        // so we can be sure that the first and last have to be the brackets [] if this is a vector
        std::vector< T > ret;
        if (str.substr(0, 1) == "["
            && str.substr(str.size() - 1, 1) == "]") {
          std::vector< std::string > tokens;
          if (str.size() > 2)
            tokens = DSC::tokenize< std::string >(str.substr(1, str.size() - 2), ";");
          for (unsigned int i = 0; i < tokens.size(); ++i)
            ret.push_back(DSC::fromString< T >(boost::algorithm::trim_copy(tokens[i])));
          for (auto i = ret.size(); i < minSize; ++i)
            ret.push_back(def);
        } else if (str.substr(0, 1) == "["
                   || str.substr(str.size() - 1, 1) == "]") {
            DUNE_THROW(Dune::RangeError, "Vectors have to be of the form '[entry_0; entry_1; ... ]'!");
        } else {
          ret = std::vector< T >(minSize, DSC::fromString< T >(boost::algorithm::trim_copy(str)));
        }
        return ret;
      }
    }
  } // std::vector< T > getVector(const std::string& key, const T def) const

  template< class T >
  Dune::DynamicVector< T > getDynVector(const std::string& _key, const size_t minSize) const
  {
    const std::vector< T > vector = getVector< T >(_key, minSize);
    Dune::DynamicVector< T > ret(vector.size());
    for (size_t ii = 0; ii < vector.size(); ++ii)
      ret[ii] = vector[ii];
    return ret;
  }

  template< class T >
  std::vector< T > getVector(const std::string& key, const unsigned int minSize) const
  {
    if (!hasKey(key)) {
      DUNE_THROW(Dune::RangeError,
                 "\n" << DSC::colorStringRed("ERROR:")
                 << " key '" << key << "' missing  in the following Dune::ParameterTree:\n" << reportString("  "));
    } else {
      std::vector< T > ret;
      const std::string str = BaseType::get< std::string >(key, "meaningless_default_value");
      // the dune parametertree strips any leading and trailing whitespace
      // so we can be sure that the first and last have to be the brackets [] if this is a vector
      if (str.substr(0, 1) == "[" && str.substr(str.size() - 1, 1) == "]") {
        const std::vector< std::string > tokens = DSC::tokenize< std::string >(str.substr(1, str.size() - 2), ";");
        for (unsigned int i = 0; i < tokens.size(); ++i)
          ret.push_back(DSC::fromString< T >(boost::algorithm::trim_copy(tokens[i])));
      } else if (minSize == 1)
        ret.push_back(DSC::fromString< T >(str));
      else
          DUNE_THROW(Dune::RangeError, "Vectors have to be of the form '[entry_0; entry_1; ... ]'!");
      if (ret.size() < minSize)
        DUNE_THROW(Dune::RangeError,
                   "\n" << DSC::colorStringRed("ERROR:")
                   << " vector '" << key
                   << "' too short (is " << ret.size() << ", should be at least " << minSize
                   << ") in the following Dune::ParameterTree :\n" << reportString("  "));
      return ret;
    }
  } // std::vector< T > getVector(const std::string& key, const T def) const

#if HAVE_EIGEN
  template< class T >
  Eigen::Matrix< T, Eigen::Dynamic, 1 > getEigenVector(const std::string& key,
                                                       const T& def,
                                                       const unsigned int minSize) const
  {
    // get corresponding vector
    std::vector< T > vec = getVector< T >(key, def, minSize);
    // create eigen vector and return
    Eigen::Matrix< T, Eigen::Dynamic, 1 > ret(vec.size());
    for (unsigned int i = 0; i < vec.size(); ++i)
      ret(i) = vec[i];
    return ret;
  }

  template< class T >
  Eigen::Matrix< T, Eigen::Dynamic, 1 > getEigenVector(const std::string& key, const unsigned int minSize) const
  {
    // get corresponding vector
    std::vector< T > vec = getVector< T >(key, minSize);
    // create eigen vector and return
    Eigen::Matrix< T, Eigen::Dynamic, 1 > ret(vec.size());
    for (unsigned int i = 0; i < vec.size(); ++i)
      ret(i) = vec[i];
    return ret;
  }
#endif // HAVE_EIGEN

  void assertKey(const std::string& key) const;
  void assertSub(const std::string& _sub) const;

  /**
    \brief      Fills a Dune::ParameterTree given a parameter file or command line arguments.
    \param[in]  argc
                From \c main()
    \param[in]  argv
                From \c main()
    \return     The Dune::ParameterTree that is to be filled.
    **/
  static ParameterTree init(int argc, char** argv, std::string filename);
  static ParameterTree init(const std::string filename);

private:
  void reportAsSub(std::ostream& stream, const std::string& prefix, const std::string& subPath) const;
  std::string findCommonPrefix(const BaseType& sub, const std::string previousPrefix = "") const;
  void reportFlatly(const BaseType& sub, const std::string& prefix = "", std::ostream& stream = std::cout) const;
}; // class ExtendedParameterTree

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_PARAMETER_TREE_HH

/** Copyright (c) 2012, Rene Milk, Felix Albrecht
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, this
   *    list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * The views and conclusions contained in the software and documentation are those
   * of the authors and should not be interpreted as representing official policies,
   * either expressed or implied, of the FreeBSD Project.
   **/
<|endoftext|>


<commit_before>/* rsspp - Copyright (C) 2008-2009 Andreas Krennmair <ak@newsbeuter.org>
 * Licensed under the MIT/X Consortium License. See file LICENSE
 * for more information.
 */

#include <config.h>
#include <rsspp.h>
#include <rsspp_internal.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <curl/curl.h>
#include <logger.h>
#include <utils.h>
#include <cstring>
#include <utils.h>

using namespace newsbeuter;

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
	std::string * pbuf = static_cast<std::string *>(userp);
	pbuf->append(static_cast<const char *>(buffer), size * nmemb);
	return size * nmemb;
}

namespace rsspp {

parser::parser(unsigned int timeout, const char * user_agent, const char * proxy, const char * proxy_auth, curl_proxytype proxy_type)
	: to(timeout), ua(user_agent), prx(proxy), prxauth(proxy_auth), prxtype(proxy_type), doc(0), lm(0) {
}

parser::~parser() {
	if (doc)
		xmlFreeDoc(doc);
}

struct header_values {
	time_t lastmodified;
	std::string etag;
};

static size_t handle_headers(void * ptr, size_t size, size_t nmemb, void * data) {
	char * header = new char[size*nmemb + 1];
	header_values * values = (header_values *)data;

	memcpy(header, ptr, size*nmemb);
	header[size*nmemb] = '\0';

	if (!strncasecmp("Last-Modified:", header, 14)) {
		values->lastmodified = curl_getdate(header+14, NULL);
		LOG(LOG_DEBUG, "handle_headers: got last-modified %s (%d)", header+14, values->lastmodified);
	} else if (!strncasecmp("ETag:",header, 5)) {
		values->etag = std::string(header+5);
		utils::trim(values->etag);
		LOG(LOG_DEBUG, "handle_headers: got etag %s", values->etag.c_str());
	}

	delete[] header;

	return size * nmemb;
}

feed parser::parse_url(const std::string& url, time_t lastmodified, const std::string& etag) {
	std::string buf;
	CURLcode ret;

	CURL * easyhandle = curl_easy_init();
	if (!easyhandle) {
		throw exception(_("couldn't initialize libcurl"));
	}

	if (ua) {
		curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, ua);
	}
	curl_easy_setopt(easyhandle, CURLOPT_URL, url.c_str());
	curl_easy_setopt(easyhandle, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &buf);
	curl_easy_setopt(easyhandle, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(easyhandle, CURLOPT_MAXREDIRS, 10);
	curl_easy_setopt(easyhandle, CURLOPT_FAILONERROR, 1);
	curl_easy_setopt(easyhandle, CURLOPT_ENCODING, "gzip, deflate");
	if (to != 0)
		curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, to);

	if (prx)
		curl_easy_setopt(easyhandle, CURLOPT_PROXY, prx);

	if (prxauth)
		curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, prxauth);

	curl_easy_setopt(easyhandle, CURLOPT_PROXYTYPE, prxtype);

	header_values hdrs = { 0, "" };

	curl_slist * custom_headers = NULL;

	if (lastmodified != 0) {
		curl_easy_setopt(easyhandle, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
		curl_easy_setopt(easyhandle, CURLOPT_TIMEVALUE, lastmodified);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERDATA, &hdrs);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, handle_headers);
	}
	if (etag.length() > 0) {
		custom_headers = curl_slist_append(custom_headers, utils::strprintf("If-None-Match: %s", etag.c_str()).c_str());
		curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, custom_headers);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERDATA, &hdrs);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, handle_headers);
	}

	ret = curl_easy_perform(easyhandle);

	lm = hdrs.lastmodified;
	et = hdrs.etag;

	if (custom_headers) {
		curl_slist_free_all(custom_headers);
	}

	LOG(LOG_DEBUG, "rsspp::parser::parse_url: ret = %d", ret);

	long status;
	curl_easy_getinfo(easyhandle, CURLINFO_HTTP_CONNECTCODE, &status);

	if (status >= 400) {
		LOG(LOG_USERERROR, _("Error: trying to download feed `%s' returned HTTP status code %ld."), url.c_str(), status);
	}

	curl_easy_cleanup(easyhandle);

	if (ret != 0) {
		LOG(LOG_ERROR, "rsspp::parser::parse_url: curl_easy_perform returned err %d: %s", ret, curl_easy_strerror(ret));
		throw exception(curl_easy_strerror(ret));
	}

	LOG(LOG_INFO, "parser::parse_url: retrieved data for %s: %s", url.c_str(), buf.c_str());

	if (buf.length() > 0) {
		LOG(LOG_DEBUG, "parser::parse_url: handing over data to parse_buffer()");
		return parse_buffer(buf.c_str(), buf.length());
	}

	return feed();
}

feed parser::parse_buffer(const char * buffer, size_t size, const char * url) {
	doc = xmlReadMemory(buffer, size, url, NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
	if (doc == NULL) {
		throw exception(_("could not parse buffer"));
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	LOG(LOG_INFO, "parser::parse_buffer: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_file(const std::string& filename) {
	doc = xmlReadFile(filename.c_str(), NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
	if (doc == NULL) {
		throw exception(_("could not parse file"));
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	LOG(LOG_INFO, "parser::parse_file: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_xmlnode(xmlNode* node) {
	feed f;

	if (node) {
		if (node->name && node->type == XML_ELEMENT_NODE) {
			if (strcmp((const char *)node->name, "rss")==0) {
				const char * version = (const char *)xmlGetProp(node, (const xmlChar *)"version");
				if (!version) {
					xmlFree((void *)version);
					throw exception(_("no RSS version"));
				}
				if (strcmp(version, "0.91")==0)
					f.rss_version = RSS_0_91;
				else if (strcmp(version, "0.92")==0)
					f.rss_version = RSS_0_92;
				else if (strcmp(version, "2.0")==0)
					f.rss_version = RSS_2_0;
				else {
					xmlFree((void *)version);
					throw exception(_("invalid RSS version"));
				}
				xmlFree((void *)version);
			} else if (strcmp((const char *)node->name, "RDF")==0) {
				f.rss_version = RSS_1_0;
			} else if (strcmp((const char *)node->name, "feed")==0) {
				if (node->ns && node->ns->href) {
					if (strcmp((const char *)node->ns->href, ATOM_0_3_URI)==0) {
						f.rss_version = ATOM_0_3;
					} else if (strcmp((const char *)node->ns->href, ATOM_1_0_URI)==0) {
						f.rss_version = ATOM_1_0;
					} else {
						throw exception(_("invalid Atom version"));
					}
				} else {
					throw exception(_("no Atom version"));
				}
			}

			std::tr1::shared_ptr<rss_parser> parser = rss_parser_factory::get_object(f, doc);

			try {
				parser->parse_feed(f, node);
			} catch (exception& e) {
				throw e;
			}
		}
	} else {
		throw exception(_("XML root node is NULL"));
	}

	return f;
}

void parser::global_init() {
	LIBXML_TEST_VERSION
	curl_global_init(CURL_GLOBAL_ALL);
}

void parser::global_cleanup() {
	xmlCleanupParser();
	curl_global_cleanup();
}

}
<commit_msg>added missing argument.<commit_after>/* rsspp - Copyright (C) 2008-2009 Andreas Krennmair <ak@newsbeuter.org>
 * Licensed under the MIT/X Consortium License. See file LICENSE
 * for more information.
 */

#include <config.h>
#include <rsspp.h>
#include <rsspp_internal.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <curl/curl.h>
#include <logger.h>
#include <utils.h>
#include <cstring>
#include <utils.h>

using namespace newsbeuter;

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
	std::string * pbuf = static_cast<std::string *>(userp);
	pbuf->append(static_cast<const char *>(buffer), size * nmemb);
	return size * nmemb;
}

namespace rsspp {

parser::parser(unsigned int timeout, const char * user_agent, const char * proxy, const char * proxy_auth, curl_proxytype proxy_type)
	: to(timeout), ua(user_agent), prx(proxy), prxauth(proxy_auth), prxtype(proxy_type), doc(0), lm(0) {
}

parser::~parser() {
	if (doc)
		xmlFreeDoc(doc);
}

struct header_values {
	time_t lastmodified;
	std::string etag;
};

static size_t handle_headers(void * ptr, size_t size, size_t nmemb, void * data) {
	char * header = new char[size*nmemb + 1];
	header_values * values = (header_values *)data;

	memcpy(header, ptr, size*nmemb);
	header[size*nmemb] = '\0';

	if (!strncasecmp("Last-Modified:", header, 14)) {
		values->lastmodified = curl_getdate(header+14, NULL);
		LOG(LOG_DEBUG, "handle_headers: got last-modified %s (%d)", header+14, values->lastmodified);
	} else if (!strncasecmp("ETag:",header, 5)) {
		values->etag = std::string(header+5);
		utils::trim(values->etag);
		LOG(LOG_DEBUG, "handle_headers: got etag %s", values->etag.c_str());
	}

	delete[] header;

	return size * nmemb;
}

feed parser::parse_url(const std::string& url, time_t lastmodified, const std::string& etag) {
	std::string buf;
	CURLcode ret;

	CURL * easyhandle = curl_easy_init();
	if (!easyhandle) {
		throw exception(_("couldn't initialize libcurl"));
	}

	if (ua) {
		curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, ua);
	}
	curl_easy_setopt(easyhandle, CURLOPT_URL, url.c_str());
	curl_easy_setopt(easyhandle, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &buf);
	curl_easy_setopt(easyhandle, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(easyhandle, CURLOPT_MAXREDIRS, 10);
	curl_easy_setopt(easyhandle, CURLOPT_FAILONERROR, 1);
	curl_easy_setopt(easyhandle, CURLOPT_ENCODING, "gzip, deflate");
	if (to != 0)
		curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, to);

	if (prx)
		curl_easy_setopt(easyhandle, CURLOPT_PROXY, prx);

	if (prxauth)
		curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, prxauth);

	curl_easy_setopt(easyhandle, CURLOPT_PROXYTYPE, prxtype);

	header_values hdrs = { 0, "" };

	curl_slist * custom_headers = NULL;

	if (lastmodified != 0) {
		curl_easy_setopt(easyhandle, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
		curl_easy_setopt(easyhandle, CURLOPT_TIMEVALUE, lastmodified);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERDATA, &hdrs);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, handle_headers);
	}
	if (etag.length() > 0) {
		custom_headers = curl_slist_append(custom_headers, utils::strprintf("If-None-Match: %s", etag.c_str()).c_str());
		curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, custom_headers);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERDATA, &hdrs);
		curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, handle_headers);
	}

	ret = curl_easy_perform(easyhandle);

	lm = hdrs.lastmodified;
	et = hdrs.etag;

	if (custom_headers) {
		curl_slist_free_all(custom_headers);
	}

	LOG(LOG_DEBUG, "rsspp::parser::parse_url: ret = %d", ret);

	long status;
	curl_easy_getinfo(easyhandle, CURLINFO_HTTP_CONNECTCODE, &status);

	if (status >= 400) {
		LOG(LOG_USERERROR, _("Error: trying to download feed `%s' returned HTTP status code %ld."), url.c_str(), status);
	}

	curl_easy_cleanup(easyhandle);

	if (ret != 0) {
		LOG(LOG_ERROR, "rsspp::parser::parse_url: curl_easy_perform returned err %d: %s", ret, curl_easy_strerror(ret));
		throw exception(curl_easy_strerror(ret));
	}

	LOG(LOG_INFO, "parser::parse_url: retrieved data for %s: %s", url.c_str(), buf.c_str());

	if (buf.length() > 0) {
		LOG(LOG_DEBUG, "parser::parse_url: handing over data to parse_buffer()");
		return parse_buffer(buf.c_str(), buf.length(), url.c_str());
	}

	return feed();
}

feed parser::parse_buffer(const char * buffer, size_t size, const char * url) {
	doc = xmlReadMemory(buffer, size, url, NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
	if (doc == NULL) {
		throw exception(_("could not parse buffer"));
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	LOG(LOG_INFO, "parser::parse_buffer: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_file(const std::string& filename) {
	doc = xmlReadFile(filename.c_str(), NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
	if (doc == NULL) {
		throw exception(_("could not parse file"));
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	LOG(LOG_INFO, "parser::parse_file: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_xmlnode(xmlNode* node) {
	feed f;

	if (node) {
		if (node->name && node->type == XML_ELEMENT_NODE) {
			if (strcmp((const char *)node->name, "rss")==0) {
				const char * version = (const char *)xmlGetProp(node, (const xmlChar *)"version");
				if (!version) {
					xmlFree((void *)version);
					throw exception(_("no RSS version"));
				}
				if (strcmp(version, "0.91")==0)
					f.rss_version = RSS_0_91;
				else if (strcmp(version, "0.92")==0)
					f.rss_version = RSS_0_92;
				else if (strcmp(version, "2.0")==0)
					f.rss_version = RSS_2_0;
				else {
					xmlFree((void *)version);
					throw exception(_("invalid RSS version"));
				}
				xmlFree((void *)version);
			} else if (strcmp((const char *)node->name, "RDF")==0) {
				f.rss_version = RSS_1_0;
			} else if (strcmp((const char *)node->name, "feed")==0) {
				if (node->ns && node->ns->href) {
					if (strcmp((const char *)node->ns->href, ATOM_0_3_URI)==0) {
						f.rss_version = ATOM_0_3;
					} else if (strcmp((const char *)node->ns->href, ATOM_1_0_URI)==0) {
						f.rss_version = ATOM_1_0;
					} else {
						throw exception(_("invalid Atom version"));
					}
				} else {
					throw exception(_("no Atom version"));
				}
			}

			std::tr1::shared_ptr<rss_parser> parser = rss_parser_factory::get_object(f, doc);

			try {
				parser->parse_feed(f, node);
			} catch (exception& e) {
				throw e;
			}
		}
	} else {
		throw exception(_("XML root node is NULL"));
	}

	return f;
}

void parser::global_init() {
	LIBXML_TEST_VERSION
	curl_global_init(CURL_GLOBAL_ALL);
}

void parser::global_cleanup() {
	xmlCleanupParser();
	curl_global_cleanup();
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Sebastian Geisler
// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.

#include <stdexcept>
#include <memory.h>

#include "ByteArray.h"
#include "Crypto.h"
#include "Conversions.h"

ByteArray::ByteArray(const Byte *data, size_t len)
: vector<Byte>(len)
{
    memcpy(&this->[0], data, len);
}

void ByteArray::operator+=(const ByteArray &other)
{
    this->insert(this->end(), other.begin(), other.end());
}

void ByteArray::operator+=(const Byte &other)
{
    this->push_back(other);
}

ByteArray ByteArray::operator+(const ByteArray &other) const
{
    ByteArray ret;
    ret.insert(ret.end(), this->begin(), this->end());
    ret.insert(ret.end(), other.begin(), other.end());
    return ret;
}

ByteArray ByteArray::operator+(const Byte other) const
{
    ByteArray ret;
    ret.insert(ret.end(), this->begin(), this->end());
    ret.insert(ret.end(), other);
    return ret;
}

std::string ByteArray::toHex() const
{
    return Conversions::toHex(*this);
}

std::string ByteArray::toBase58() const
{
    return Conversions::toBase58(*this);
}

std::string ByteArray::toBase58Check(Byte version) const
{
    return Conversions::toBase58Check(*this, version);
}

ByteArray ByteArray::sha256() const
{
    return Crypto::sha256(*this);
}

ByteArray ByteArray::ripemd160() const
{
    return Crypto::ripemd160(*this);
}

ByteArray ByteArray::getSection(ByteArray::size_type begin, ByteArray::size_type len)
{
    if (begin + len > size())
        throw std::range_error("section not in bounds of ByteArray");

    if (len == 0)
        return ByteArray();

    ByteArray ret;
    ret.insert(ret.end(), this->begin() + begin, this->begin() + (begin + len));

    return ret;
}

uint16_t ByteArray::toUInt16()
{
    return Conversions::toUInt16(*this);
}

uint32_t ByteArray::toUInt32()
{
    return Conversions::toUInt32(*this);
}

uint64_t ByteArray::toUInt64()
{
    return Conversions::toUInt64(*this);
}
<commit_msg>fixed syntax error<commit_after>// Copyright (c) 2015 Sebastian Geisler
// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.

#include <stdexcept>
#include <memory.h>

#include "ByteArray.h"
#include "Crypto.h"
#include "Conversions.h"

ByteArray::ByteArray(const Byte *data, size_t len)
: vector<Byte>(len)
{
    memcpy(&(*this)[0], data, len);
}

void ByteArray::operator+=(const ByteArray &other)
{
    this->insert(this->end(), other.begin(), other.end());
}

void ByteArray::operator+=(const Byte &other)
{
    this->push_back(other);
}

ByteArray ByteArray::operator+(const ByteArray &other) const
{
    ByteArray ret;
    ret.insert(ret.end(), this->begin(), this->end());
    ret.insert(ret.end(), other.begin(), other.end());
    return ret;
}

ByteArray ByteArray::operator+(const Byte other) const
{
    ByteArray ret;
    ret.insert(ret.end(), this->begin(), this->end());
    ret.insert(ret.end(), other);
    return ret;
}

std::string ByteArray::toHex() const
{
    return Conversions::toHex(*this);
}

std::string ByteArray::toBase58() const
{
    return Conversions::toBase58(*this);
}

std::string ByteArray::toBase58Check(Byte version) const
{
    return Conversions::toBase58Check(*this, version);
}

ByteArray ByteArray::sha256() const
{
    return Crypto::sha256(*this);
}

ByteArray ByteArray::ripemd160() const
{
    return Crypto::ripemd160(*this);
}

ByteArray ByteArray::getSection(ByteArray::size_type begin, ByteArray::size_type len)
{
    if (begin + len > size())
        throw std::range_error("section not in bounds of ByteArray");

    if (len == 0)
        return ByteArray();

    ByteArray ret;
    ret.insert(ret.end(), this->begin() + begin, this->begin() + (begin + len));

    return ret;
}

uint16_t ByteArray::toUInt16()
{
    return Conversions::toUInt16(*this);
}

uint32_t ByteArray::toUInt32()
{
    return Conversions::toUInt32(*this);
}

uint64_t ByteArray::toUInt64()
{
    return Conversions::toUInt64(*this);
}
<|endoftext|>