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

#include "common.h"
#include "controllerclientimpl.h"
#include "binpickingtaskzmq.h"
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/exceptions.hpp>
#include "mujincontrollerclient/mujinzmq.h"

#include <algorithm> // find

#include "logging.h"

MUJIN_LOGGER("mujin.controllerclientcpp.binpickingtask.zmq");

namespace
{
void ConvertTimestampToFloat(const std::string& in,
                             std::stringstream& outss)
{
    const std::size_t len = in.size();
    std::size_t processed = 0;
    while (processed != std::string::npos && processed < len) {
        const std::size_t deltabegin = in.substr(processed, len).find("\"timestamp\":");
        if (deltabegin == std::string::npos) {
            outss << in.substr(processed, len);
            return;
        }
        const std::size_t timestampbegin = processed + deltabegin;
        const std::size_t comma = in.substr(timestampbegin, len).find(",");
        const std::size_t closingCurly = in.substr(timestampbegin, len).find("}");
        if (comma == std::string::npos && closingCurly == std::string::npos)
        {
            throw mujinclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinclient::MEC_Failed);
        }
        const std::size_t timestampend = timestampbegin + std::min(comma, closingCurly);
        if (timestampend == std::string::npos) {
            throw mujinclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinclient::MEC_Failed);
        }
        const std::size_t period = in.substr(timestampbegin, len).find(".");

        if (period == std::string::npos || timestampbegin + period > timestampend) {
            // no comma, assume this is in integet format. so add period to make it a float format.
            outss << in.substr(processed, timestampend - processed) << ".";
        }
        else {
            // already floating format. keep it that way
            outss << in.substr(processed, timestampend - processed);
        }
        processed = timestampend;
    }
}
}

namespace mujinclient {
using namespace utils;

class ZmqMujinControllerClient : public mujinzmq::ZmqClient
{

public:
    ZmqMujinControllerClient(boost::shared_ptr<zmq::context_t> context, const std::string& host, const int port);

    virtual ~ZmqMujinControllerClient();

};

ZmqMujinControllerClient::ZmqMujinControllerClient(boost::shared_ptr<zmq::context_t> context, const std::string& host, const int port) : ZmqClient(host, port)
{
    _InitializeSocket(context);
}

ZmqMujinControllerClient::~ZmqMujinControllerClient()
{
    // _DestroySocket() is called in  ~ZmqClient()
}

BinPickingTaskZmqResource::BinPickingTaskZmqResource(ControllerClientPtr c, const std::string& pk, const std::string& scenepk, const std::string& tasktype) : BinPickingTaskResource(c, pk, scenepk, tasktype)
{
}

BinPickingTaskZmqResource::~BinPickingTaskZmqResource()
{
}

void BinPickingTaskZmqResource::Initialize(const std::string& defaultTaskParameters,  const int zmqPort, const int heartbeatPort, boost::shared_ptr<zmq::context_t> zmqcontext, const bool initializezmq, const double reinitializetimeout, const double timeout, const std::string& userinfo, const std::string& slaverequestid)
{
    BinPickingTaskResource::Initialize(defaultTaskParameters, zmqPort, heartbeatPort, zmqcontext, initializezmq, reinitializetimeout, timeout, userinfo, slaverequestid);

    if (initializezmq) {
        InitializeZMQ(reinitializetimeout, timeout);
    }

    _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
    if (!_zmqmujincontrollerclient) {
        throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed);
    }
    if (!_pHeartbeatMonitorThread) {
        _bShutdownHeartbeatMonitor = false;
        if (reinitializetimeout > 0 ) {
            _pHeartbeatMonitorThread.reset(new boost::thread(boost::bind(&BinPickingTaskZmqResource::_HeartbeatMonitorThread, this, reinitializetimeout, timeout)));
        }
    }
}

boost::property_tree::ptree BinPickingTaskZmqResource::ExecuteCommand(const std::string& taskparameters, const double timeout /* [sec] */, const bool getresult)
{
    if (!_bIsInitialized) {
        throw MujinException("BinPicking task is not initialized, please call Initialzie() first.", MEC_Failed);
    }

    if (!_zmqmujincontrollerclient) {
        MUJIN_LOG_ERROR("zmqcontrollerclient is not initialized! initialize");
        _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
    }

    std::stringstream ss;
    ss << "{\"fnname\": \"";
    if (_tasktype == "binpicking") {
        ss << "binpicking.";
    }
    ss << "RunCommand\", \"taskparams\": {\"tasktype\": \"" << _tasktype << "\", ";

    ss << "\"taskparameters\": " << taskparameters << ", ";
    ss << "\"sceneparams\": " << _sceneparams_json << "}, ";
    ss << "\"userinfo\": " << _userinfo_json;
    if (_slaverequestid != "") {
        ss << ", " << GetJsonString("slaverequestid", _slaverequestid);
    }
    ss << "}";
    std::string command = ss.str();
    //    std::cout << "Sending " << command << " from " << __func__ << std::endl;

    //std::string task = "{\"tasktype\": \"binpicking\", \"taskparameters\": " + command + "}";
    boost::property_tree::ptree pt;
    if (getresult) {
        std::stringstream result_ss;

        try{
            result_ss << _zmqmujincontrollerclient->Call(command, timeout);
        }
        catch (const MujinException& e) {
            MUJIN_LOG_ERROR(e.what());
            if (e.GetCode() == MEC_ZMQNoResponse) {
                MUJIN_LOG_INFO("reinitializing zmq connection with the slave");
                _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
                if (!_zmqmujincontrollerclient) {
                    throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed);
                }
            }
        }

        try {
            // temporary fix until we move on to rapid json
            std::stringstream result_ss_float_timestamp;
            ConvertTimestampToFloat(result_ss.str(), result_ss_float_timestamp);
            std::cout << result_ss.str() << std::endl
                      << result_ss_float_timestamp.str() << std::endl;
            boost::property_tree::read_json(result_ss_float_timestamp, pt);
            boost::property_tree::ptree::const_assoc_iterator iterror = pt.find("error");
            if( iterror != pt.not_found() ) {
                boost::optional<std::string> erroroptional = iterror->second.get_optional<std::string>("errorcode");
                boost::optional<std::string> descriptionoptional = iterror->second.get_optional<std::string>("description");
                if (!!erroroptional && erroroptional.get().size() > 0 ) {
                    std::string serror;
                    if (!!descriptionoptional && descriptionoptional.get().size() > 0 ) {
                        serror = descriptionoptional.get();
                    }
                    else {
                        serror = erroroptional.get();
                    }
                    if( serror.size() > 1000 ) {
                        MUJIN_LOG_ERROR(str(boost::format("truncated original error message from %d")%serror.size()));
                        serror = serror.substr(0,1000);
                    }

                    throw MujinException(str(boost::format("Error when calling binpicking.RunCommand: %s")%serror), MEC_BinPickingError);
                }
            }
        } catch (boost::property_tree::ptree_error& e) {
            throw MujinException(boost::str(boost::format("Failed to parse json which is received from mujin controller: \nreceived message: %s \nerror message: %s")%result_ss.str()%e.what()), MEC_Failed);
        }
    } else {
        try{
            _zmqmujincontrollerclient->Call(command, timeout);
            // TODO since not getting response, internal zmq will be in a bad state, have to recreate
        }
        catch (const MujinException& e) {
            MUJIN_LOG_ERROR(e.what());
            if (e.GetCode() == MEC_ZMQNoResponse) {
                MUJIN_LOG_INFO("reinitializing zmq connection with the slave");
                _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
                if (!_zmqmujincontrollerclient) {
                    throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed);
                }
            }
        }
    }
    return pt;
}

void BinPickingTaskZmqResource::InitializeZMQ(const double reinitializetimeout, const double timeout)
{
}

void BinPickingTaskZmqResource::_HeartbeatMonitorThread(const double reinitializetimeout, const double commandtimeout)
{
    boost::shared_ptr<zmq::socket_t>  socket;
    boost::property_tree::ptree pt;
    BinPickingTaskResource::ResultHeartBeat heartbeat;
    heartbeat._slaverequestid = _slaverequestid;
    while (!_bShutdownHeartbeatMonitor) {
        if (!!socket) {
            socket->close();
            socket.reset();
        }
        socket.reset(new zmq::socket_t((*_zmqcontext.get()),ZMQ_SUB));
        std::stringstream ss;
        ss << _heartbeatPort;
        socket->connect (("tcp://"+ _mujinControllerIp+":"+ss.str()).c_str());
        socket->setsockopt(ZMQ_SUBSCRIBE, "", 0);

        zmq::pollitem_t pollitem;
        memset(&pollitem, 0, sizeof(zmq::pollitem_t));
        pollitem.socket = socket->operator void*();
        pollitem.events = ZMQ_POLLIN;
        unsigned long long lastheartbeat = GetMilliTime();
        while (!_bShutdownHeartbeatMonitor && (GetMilliTime() - lastheartbeat) / 1000.0f < reinitializetimeout) {
            zmq::poll(&pollitem,1, 50); // wait 50 ms for message
            if (pollitem.revents & ZMQ_POLLIN) {
                zmq::message_t reply;
                socket->recv(&reply);
                std::string replystring((char *) reply.data (), (size_t) reply.size());
#ifdef _WIN32
                // sometimes buffer can container \n or \\, which windows boost property_tree does not like
                std::string newbuffer;
                std::vector< std::pair<std::string, std::string> > serachpairs(1);
                serachpairs[0].first = "\\"; serachpairs[0].second = "";
                SearchAndReplace(newbuffer, replystring, serachpairs);
                std::stringstream replystring_ss(newbuffer);
#else
                std::stringstream replystring_ss(replystring);
#endif
                try{
                    boost::property_tree::read_json(replystring_ss, pt);
                }
                catch (std::exception const &e) {
                    MUJIN_LOG_ERROR("HeartBeat reply is not JSON");
                    MUJIN_LOG_ERROR(e.what());
                    continue;
                }
                heartbeat.Parse(pt);
                {
                    boost::mutex::scoped_lock lock(_mutexTaskState);
                    _taskstate = heartbeat.taskstate;
                }
                //BINPICKING_LOG_ERROR(replystring);

                if (heartbeat.status != std::string("lost") && heartbeat.status.size() > 1) {
                    lastheartbeat = GetMilliTime();
                }
            }
        }
        if (!_bShutdownHeartbeatMonitor) {
            std::stringstream ss;
            ss << (double)((GetMilliTime() - lastheartbeat)/1000.0f) << " seconds passed since last heartbeat signal, re-intializing ZMQ server.";
            MUJIN_LOG_INFO(ss.str());
        }
    }
}

} // end namespace mujinclient
<commit_msg>compile error fix for windows<commit_after>// -*- coding: utf-8 -*-
// Copyright (C) 2012-2014 MUJIN Inc. <rosen.diankov@mujin.co.jp>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "common.h"
#include "controllerclientimpl.h"
#include "binpickingtaskzmq.h"
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/exceptions.hpp>
#include "mujincontrollerclient/mujinzmq.h"

#include <algorithm> // find

#include "logging.h"

MUJIN_LOGGER("mujin.controllerclientcpp.binpickingtask.zmq");

namespace
{
void ConvertTimestampToFloat(const std::string& in,
                             std::stringstream& outss)
{
    const std::size_t len = in.size();
    std::size_t processed = 0;
    while (processed != std::string::npos && processed < len) {
        const std::size_t deltabegin = in.substr(processed, len).find("\"timestamp\":");
        if (deltabegin == std::string::npos) {
            outss << in.substr(processed, len);
            return;
        }
        const std::size_t timestampbegin = processed + deltabegin;
        const std::size_t comma = in.substr(timestampbegin, len).find(",");
        const std::size_t closingCurly = in.substr(timestampbegin, len).find("}");
        if (comma == std::string::npos && closingCurly == std::string::npos)
        {
            throw mujinclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinclient::MEC_Failed);
        }
        const std::size_t timestampend = timestampbegin + (comma < closingCurly ? comma : closingCurly);
        if (timestampend == std::string::npos) {
            throw mujinclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinclient::MEC_Failed);
        }
        const std::size_t period = in.substr(timestampbegin, len).find(".");

        if (period == std::string::npos || timestampbegin + period > timestampend) {
            // no comma, assume this is in integet format. so add period to make it a float format.
            outss << in.substr(processed, timestampend - processed) << ".";
        }
        else {
            // already floating format. keep it that way
            outss << in.substr(processed, timestampend - processed);
        }
        processed = timestampend;
    }
}
}

namespace mujinclient {
using namespace utils;

class ZmqMujinControllerClient : public mujinzmq::ZmqClient
{

public:
    ZmqMujinControllerClient(boost::shared_ptr<zmq::context_t> context, const std::string& host, const int port);

    virtual ~ZmqMujinControllerClient();

};

ZmqMujinControllerClient::ZmqMujinControllerClient(boost::shared_ptr<zmq::context_t> context, const std::string& host, const int port) : ZmqClient(host, port)
{
    _InitializeSocket(context);
}

ZmqMujinControllerClient::~ZmqMujinControllerClient()
{
    // _DestroySocket() is called in  ~ZmqClient()
}

BinPickingTaskZmqResource::BinPickingTaskZmqResource(ControllerClientPtr c, const std::string& pk, const std::string& scenepk, const std::string& tasktype) : BinPickingTaskResource(c, pk, scenepk, tasktype)
{
}

BinPickingTaskZmqResource::~BinPickingTaskZmqResource()
{
}

void BinPickingTaskZmqResource::Initialize(const std::string& defaultTaskParameters,  const int zmqPort, const int heartbeatPort, boost::shared_ptr<zmq::context_t> zmqcontext, const bool initializezmq, const double reinitializetimeout, const double timeout, const std::string& userinfo, const std::string& slaverequestid)
{
    BinPickingTaskResource::Initialize(defaultTaskParameters, zmqPort, heartbeatPort, zmqcontext, initializezmq, reinitializetimeout, timeout, userinfo, slaverequestid);

    if (initializezmq) {
        InitializeZMQ(reinitializetimeout, timeout);
    }

    _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
    if (!_zmqmujincontrollerclient) {
        throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed);
    }
    if (!_pHeartbeatMonitorThread) {
        _bShutdownHeartbeatMonitor = false;
        if (reinitializetimeout > 0 ) {
            _pHeartbeatMonitorThread.reset(new boost::thread(boost::bind(&BinPickingTaskZmqResource::_HeartbeatMonitorThread, this, reinitializetimeout, timeout)));
        }
    }
}

boost::property_tree::ptree BinPickingTaskZmqResource::ExecuteCommand(const std::string& taskparameters, const double timeout /* [sec] */, const bool getresult)
{
    if (!_bIsInitialized) {
        throw MujinException("BinPicking task is not initialized, please call Initialzie() first.", MEC_Failed);
    }

    if (!_zmqmujincontrollerclient) {
        MUJIN_LOG_ERROR("zmqcontrollerclient is not initialized! initialize");
        _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
    }

    std::stringstream ss;
    ss << "{\"fnname\": \"";
    if (_tasktype == "binpicking") {
        ss << "binpicking.";
    }
    ss << "RunCommand\", \"taskparams\": {\"tasktype\": \"" << _tasktype << "\", ";

    ss << "\"taskparameters\": " << taskparameters << ", ";
    ss << "\"sceneparams\": " << _sceneparams_json << "}, ";
    ss << "\"userinfo\": " << _userinfo_json;
    if (_slaverequestid != "") {
        ss << ", " << GetJsonString("slaverequestid", _slaverequestid);
    }
    ss << "}";
    std::string command = ss.str();
    //    std::cout << "Sending " << command << " from " << __func__ << std::endl;

    //std::string task = "{\"tasktype\": \"binpicking\", \"taskparameters\": " + command + "}";
    boost::property_tree::ptree pt;
    if (getresult) {
        std::stringstream result_ss;

        try{
            result_ss << _zmqmujincontrollerclient->Call(command, timeout);
        }
        catch (const MujinException& e) {
            MUJIN_LOG_ERROR(e.what());
            if (e.GetCode() == MEC_ZMQNoResponse) {
                MUJIN_LOG_INFO("reinitializing zmq connection with the slave");
                _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
                if (!_zmqmujincontrollerclient) {
                    throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed);
                }
            }
        }

        try {
            // temporary fix until we move on to rapid json
            std::stringstream result_ss_float_timestamp;
            ConvertTimestampToFloat(result_ss.str(), result_ss_float_timestamp);
            std::cout << result_ss.str() << std::endl
                      << result_ss_float_timestamp.str() << std::endl;
            boost::property_tree::read_json(result_ss_float_timestamp, pt);
            boost::property_tree::ptree::const_assoc_iterator iterror = pt.find("error");
            if( iterror != pt.not_found() ) {
                boost::optional<std::string> erroroptional = iterror->second.get_optional<std::string>("errorcode");
                boost::optional<std::string> descriptionoptional = iterror->second.get_optional<std::string>("description");
                if (!!erroroptional && erroroptional.get().size() > 0 ) {
                    std::string serror;
                    if (!!descriptionoptional && descriptionoptional.get().size() > 0 ) {
                        serror = descriptionoptional.get();
                    }
                    else {
                        serror = erroroptional.get();
                    }
                    if( serror.size() > 1000 ) {
                        MUJIN_LOG_ERROR(str(boost::format("truncated original error message from %d")%serror.size()));
                        serror = serror.substr(0,1000);
                    }

                    throw MujinException(str(boost::format("Error when calling binpicking.RunCommand: %s")%serror), MEC_BinPickingError);
                }
            }
        } catch (boost::property_tree::ptree_error& e) {
            throw MujinException(boost::str(boost::format("Failed to parse json which is received from mujin controller: \nreceived message: %s \nerror message: %s")%result_ss.str()%e.what()), MEC_Failed);
        }
    } else {
        try{
            _zmqmujincontrollerclient->Call(command, timeout);
            // TODO since not getting response, internal zmq will be in a bad state, have to recreate
        }
        catch (const MujinException& e) {
            MUJIN_LOG_ERROR(e.what());
            if (e.GetCode() == MEC_ZMQNoResponse) {
                MUJIN_LOG_INFO("reinitializing zmq connection with the slave");
                _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort));
                if (!_zmqmujincontrollerclient) {
                    throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed);
                }
            }
        }
    }
    return pt;
}

void BinPickingTaskZmqResource::InitializeZMQ(const double reinitializetimeout, const double timeout)
{
}

void BinPickingTaskZmqResource::_HeartbeatMonitorThread(const double reinitializetimeout, const double commandtimeout)
{
    boost::shared_ptr<zmq::socket_t>  socket;
    boost::property_tree::ptree pt;
    BinPickingTaskResource::ResultHeartBeat heartbeat;
    heartbeat._slaverequestid = _slaverequestid;
    while (!_bShutdownHeartbeatMonitor) {
        if (!!socket) {
            socket->close();
            socket.reset();
        }
        socket.reset(new zmq::socket_t((*_zmqcontext.get()),ZMQ_SUB));
        std::stringstream ss;
        ss << _heartbeatPort;
        socket->connect (("tcp://"+ _mujinControllerIp+":"+ss.str()).c_str());
        socket->setsockopt(ZMQ_SUBSCRIBE, "", 0);

        zmq::pollitem_t pollitem;
        memset(&pollitem, 0, sizeof(zmq::pollitem_t));
        pollitem.socket = socket->operator void*();
        pollitem.events = ZMQ_POLLIN;
        unsigned long long lastheartbeat = GetMilliTime();
        while (!_bShutdownHeartbeatMonitor && (GetMilliTime() - lastheartbeat) / 1000.0f < reinitializetimeout) {
            zmq::poll(&pollitem,1, 50); // wait 50 ms for message
            if (pollitem.revents & ZMQ_POLLIN) {
                zmq::message_t reply;
                socket->recv(&reply);
                std::string replystring((char *) reply.data (), (size_t) reply.size());
#ifdef _WIN32
                // sometimes buffer can container \n or \\, which windows boost property_tree does not like
                std::string newbuffer;
                std::vector< std::pair<std::string, std::string> > serachpairs(1);
                serachpairs[0].first = "\\"; serachpairs[0].second = "";
                SearchAndReplace(newbuffer, replystring, serachpairs);
                std::stringstream replystring_ss(newbuffer);
#else
                std::stringstream replystring_ss(replystring);
#endif
                try{
                    boost::property_tree::read_json(replystring_ss, pt);
                }
                catch (std::exception const &e) {
                    MUJIN_LOG_ERROR("HeartBeat reply is not JSON");
                    MUJIN_LOG_ERROR(e.what());
                    continue;
                }
                heartbeat.Parse(pt);
                {
                    boost::mutex::scoped_lock lock(_mutexTaskState);
                    _taskstate = heartbeat.taskstate;
                }
                //BINPICKING_LOG_ERROR(replystring);

                if (heartbeat.status != std::string("lost") && heartbeat.status.size() > 1) {
                    lastheartbeat = GetMilliTime();
                }
            }
        }
        if (!_bShutdownHeartbeatMonitor) {
            std::stringstream ss;
            ss << (double)((GetMilliTime() - lastheartbeat)/1000.0f) << " seconds passed since last heartbeat signal, re-intializing ZMQ server.";
            MUJIN_LOG_INFO(ss.str());
        }
    }
}

} // end namespace mujinclient
<|endoftext|>


<commit_before>#include "common/runtime/runtime_features.h"

#include "absl/strings/match.h"

namespace Envoy {
namespace Runtime {

bool isRuntimeFeature(absl::string_view feature) {
  return RuntimeFeaturesDefaults::get().enabledByDefault(feature) ||
         RuntimeFeaturesDefaults::get().existsButDisabled(feature);
}

bool runtimeFeatureEnabled(absl::string_view feature) {
  ASSERT(isRuntimeFeature(feature));
  if (Runtime::LoaderSingleton::getExisting()) {
    return Runtime::LoaderSingleton::getExisting()->threadsafeSnapshot()->runtimeFeatureEnabled(
        feature);
  }
  ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::runtime), warn,
                      "Unable to use runtime singleton for feature {}", feature);
  return RuntimeFeaturesDefaults::get().enabledByDefault(feature);
}

uint64_t getInteger(absl::string_view feature, uint64_t default_value) {
  ASSERT(absl::StartsWith(feature, "envoy."));
  if (Runtime::LoaderSingleton::getExisting()) {
    return Runtime::LoaderSingleton::getExisting()->threadsafeSnapshot()->getInteger(
        std::string(feature), default_value);
  }
  ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::runtime), warn,
                      "Unable to use runtime singleton for feature {}", feature);
  return default_value;
}

// Add additional features here to enable the new code paths by default.
//
// Per documentation in CONTRIBUTING.md is expected that new high risk code paths be guarded
// by runtime feature guards, i.e
//
// if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.my_feature_name")) {
//   [new code path]
// else {
//   [old_code_path]
// }
//
// Runtime features are false by default, so the old code path is exercised.
// To make a runtime feature true by default, add it to the array below.
// New features should be true-by-default for an Envoy release cycle before the
// old code path is removed.
//
// If issues are found that require a runtime feature to be disabled, it should be reported
// ASAP by filing a bug on github. Overriding non-buggy code is strongly discouraged to avoid the
// problem of the bugs being found after the old code path has been removed.
constexpr const char* runtime_features[] = {
    // Enabled
    "envoy.reloadable_features.http1_flood_protection",
    "envoy.reloadable_features.test_feature_true",
    // Begin alphabetically sorted section.
    "envoy.deprecated_features.allow_deprecated_extension_names",
    "envoy.reloadable_features.activate_fds_next_event_loop",
    "envoy.reloadable_features.activate_timers_next_event_loop",
    "envoy.reloadable_features.allow_500_after_100",
    "envoy.reloadable_features.allow_prefetch",
    "envoy.reloadable_features.allow_response_for_timeout",
    "envoy.reloadable_features.consume_all_retry_headers",
    "envoy.reloadable_features.disallow_unbounded_access_logs",
    "envoy.reloadable_features.early_errors_via_hcm",
    "envoy.reloadable_features.enable_deprecated_v2_api_warning",
    "envoy.reloadable_features.enable_dns_cache_circuit_breakers",
    "envoy.reloadable_features.ext_authz_http_service_enable_case_sensitive_string_matcher",
    "envoy.reloadable_features.fix_upgrade_response",
    "envoy.reloadable_features.fix_wildcard_matching",
    "envoy.reloadable_features.fixed_connection_close",
    "envoy.reloadable_features.hcm_stream_error_on_invalid_message",
    "envoy.reloadable_features.http_default_alpn",
    "envoy.reloadable_features.http_transport_failure_reason_in_body",
    "envoy.reloadable_features.http2_skip_encoding_empty_trailers",
    "envoy.reloadable_features.listener_in_place_filterchain_update",
    "envoy.reloadable_features.overload_manager_disable_keepalive_drain_http2",
    "envoy.reloadable_features.preserve_query_string_in_path_redirects",
    "envoy.reloadable_features.preserve_upstream_date",
    "envoy.reloadable_features.stop_faking_paths",
    "envoy.reloadable_features.strict_1xx_and_204_response_headers",
    "envoy.reloadable_features.tls_use_io_handle_bio",
};

// This is a section for officially sanctioned runtime features which are too
// high risk to be enabled by default. Examples where we have opted to land
// features without enabling by default are swapping the underlying buffer
// implementation or the HTTP/1.1 codec implementation. Most features should be
// enabled by default.
//
// When features are added here, there should be a tracking bug assigned to the
// code owner to flip the default after sufficient testing.
constexpr const char* disabled_runtime_features[] = {
    // TODO(asraa) flip this feature after codec errors are handled
    "envoy.reloadable_features.new_codec_behavior",
    // TODO(alyssawilk) flip true after the release.
    "envoy.reloadable_features.new_tcp_connection_pool",
    // Sentinel and test flag.
    "envoy.reloadable_features.test_feature_false",
};

RuntimeFeatures::RuntimeFeatures() {
  for (auto& feature : runtime_features) {
    enabled_features_.insert(feature);
  }
  for (auto& feature : disabled_runtime_features) {
    disabled_features_.insert(feature);
  }
}

} // namespace Runtime
} // namespace Envoy
<commit_msg>tcp: switching to the new pool (#13012)<commit_after>#include "common/runtime/runtime_features.h"

#include "absl/strings/match.h"

namespace Envoy {
namespace Runtime {

bool isRuntimeFeature(absl::string_view feature) {
  return RuntimeFeaturesDefaults::get().enabledByDefault(feature) ||
         RuntimeFeaturesDefaults::get().existsButDisabled(feature);
}

bool runtimeFeatureEnabled(absl::string_view feature) {
  ASSERT(isRuntimeFeature(feature));
  if (Runtime::LoaderSingleton::getExisting()) {
    return Runtime::LoaderSingleton::getExisting()->threadsafeSnapshot()->runtimeFeatureEnabled(
        feature);
  }
  ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::runtime), warn,
                      "Unable to use runtime singleton for feature {}", feature);
  return RuntimeFeaturesDefaults::get().enabledByDefault(feature);
}

uint64_t getInteger(absl::string_view feature, uint64_t default_value) {
  ASSERT(absl::StartsWith(feature, "envoy."));
  if (Runtime::LoaderSingleton::getExisting()) {
    return Runtime::LoaderSingleton::getExisting()->threadsafeSnapshot()->getInteger(
        std::string(feature), default_value);
  }
  ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::runtime), warn,
                      "Unable to use runtime singleton for feature {}", feature);
  return default_value;
}

// Add additional features here to enable the new code paths by default.
//
// Per documentation in CONTRIBUTING.md is expected that new high risk code paths be guarded
// by runtime feature guards, i.e
//
// if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.my_feature_name")) {
//   [new code path]
// else {
//   [old_code_path]
// }
//
// Runtime features are false by default, so the old code path is exercised.
// To make a runtime feature true by default, add it to the array below.
// New features should be true-by-default for an Envoy release cycle before the
// old code path is removed.
//
// If issues are found that require a runtime feature to be disabled, it should be reported
// ASAP by filing a bug on github. Overriding non-buggy code is strongly discouraged to avoid the
// problem of the bugs being found after the old code path has been removed.
constexpr const char* runtime_features[] = {
    // Enabled
    "envoy.reloadable_features.http1_flood_protection",
    "envoy.reloadable_features.test_feature_true",
    // Begin alphabetically sorted section.
    "envoy.deprecated_features.allow_deprecated_extension_names",
    "envoy.reloadable_features.activate_fds_next_event_loop",
    "envoy.reloadable_features.activate_timers_next_event_loop",
    "envoy.reloadable_features.allow_500_after_100",
    "envoy.reloadable_features.allow_prefetch",
    "envoy.reloadable_features.allow_response_for_timeout",
    "envoy.reloadable_features.consume_all_retry_headers",
    "envoy.reloadable_features.disallow_unbounded_access_logs",
    "envoy.reloadable_features.early_errors_via_hcm",
    "envoy.reloadable_features.enable_deprecated_v2_api_warning",
    "envoy.reloadable_features.enable_dns_cache_circuit_breakers",
    "envoy.reloadable_features.ext_authz_http_service_enable_case_sensitive_string_matcher",
    "envoy.reloadable_features.fix_upgrade_response",
    "envoy.reloadable_features.fix_wildcard_matching",
    "envoy.reloadable_features.fixed_connection_close",
    "envoy.reloadable_features.hcm_stream_error_on_invalid_message",
    "envoy.reloadable_features.http_default_alpn",
    "envoy.reloadable_features.http_transport_failure_reason_in_body",
    "envoy.reloadable_features.http2_skip_encoding_empty_trailers",
    "envoy.reloadable_features.listener_in_place_filterchain_update",
    "envoy.reloadable_features.new_tcp_connection_pool",
    "envoy.reloadable_features.overload_manager_disable_keepalive_drain_http2",
    "envoy.reloadable_features.preserve_query_string_in_path_redirects",
    "envoy.reloadable_features.preserve_upstream_date",
    "envoy.reloadable_features.stop_faking_paths",
    "envoy.reloadable_features.strict_1xx_and_204_response_headers",
    "envoy.reloadable_features.tls_use_io_handle_bio",
};

// This is a section for officially sanctioned runtime features which are too
// high risk to be enabled by default. Examples where we have opted to land
// features without enabling by default are swapping the underlying buffer
// implementation or the HTTP/1.1 codec implementation. Most features should be
// enabled by default.
//
// When features are added here, there should be a tracking bug assigned to the
// code owner to flip the default after sufficient testing.
constexpr const char* disabled_runtime_features[] = {
    // TODO(asraa) flip this feature after codec errors are handled
    "envoy.reloadable_features.new_codec_behavior",
    // Sentinel and test flag.
    "envoy.reloadable_features.test_feature_false",
};

RuntimeFeatures::RuntimeFeatures() {
  for (auto& feature : runtime_features) {
    enabled_features_.insert(feature);
  }
  for (auto& feature : disabled_runtime_features) {
    disabled_features_.insert(feature);
  }
}

} // namespace Runtime
} // namespace Envoy
<|endoftext|>


<commit_before>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/dos_header.hpp"

#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE dos_header
#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/test/unit_test.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/module.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/module_list.hpp"
#include "hadesmem/pelib/pe_file.hpp"

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(dos_header)
{
  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);

  hadesmem::DosHeader dos_header_1(process, pe_file_1);

  hadesmem::DosHeader dos_header_2(dos_header_1);
  BOOST_CHECK_EQUAL(dos_header_1, dos_header_2);
  dos_header_1 = dos_header_2;
  BOOST_CHECK_EQUAL(dos_header_1, dos_header_2);
  hadesmem::DosHeader dos_header_3(std::move(dos_header_2));
  BOOST_CHECK_EQUAL(dos_header_3, dos_header_1);
  dos_header_2 = std::move(dos_header_3);
  BOOST_CHECK_EQUAL(dos_header_1, dos_header_2);

  hadesmem::ModuleList modules(process);
  for (auto const& mod : modules)
  {
    // TODO: Also test FileType_Data
    hadesmem::PeFile const pe_file(process, mod.GetHandle(),
      hadesmem::PeFileType::Data);

    hadesmem::DosHeader dos_header(process, pe_file);

    auto const dos_header_raw = hadesmem::Read<IMAGE_DOS_HEADER>(process,
      dos_header.GetBase());

    BOOST_CHECK_EQUAL(dos_header.IsValid(), true);
    dos_header.EnsureValid();
    dos_header.SetMagic(dos_header.GetMagic());
    dos_header.SetBytesOnLastPage(dos_header.GetBytesOnLastPage());
    dos_header.SetPagesInFile(dos_header.GetPagesInFile());
    dos_header.SetRelocations(dos_header.GetRelocations());
    dos_header.SetSizeOfHeaderInParagraphs(dos_header.
      GetSizeOfHeaderInParagraphs());
    dos_header.SetMinExtraParagraphs(dos_header.GetMinExtraParagraphs());
    dos_header.SetMaxExtraParagraphs(dos_header.GetMaxExtraParagraphs());
    dos_header.SetInitialSS(dos_header.GetInitialSS());
    dos_header.SetInitialSP(dos_header.GetInitialSP());
    dos_header.SetChecksum(dos_header.GetChecksum());
    dos_header.SetInitialIP(dos_header.GetInitialIP());
    dos_header.SetInitialCS(dos_header.GetInitialCS());
    dos_header.SetRelocTableFileAddr(dos_header.GetRelocTableFileAddr());
    dos_header.SetOverlayNum(dos_header.GetOverlayNum());
    dos_header.SetReservedWords1(dos_header.GetReservedWords1());
    dos_header.SetOEMID(dos_header.GetOEMID());
    dos_header.SetOEMInfo(dos_header.GetOEMInfo());
    dos_header.SetReservedWords2(dos_header.GetReservedWords2());
    dos_header.SetNewHeaderOffset(dos_header.GetNewHeaderOffset());

    auto const dos_header_raw_new = hadesmem::Read<IMAGE_DOS_HEADER>(process,
      pe_file.GetBase());

    BOOST_CHECK_EQUAL(std::memcmp(&dos_header_raw, &dos_header_raw_new,
      sizeof(dos_header_raw)), 0);

    std::stringstream test_str_1;
    test_str_1.imbue(std::locale::classic());
    test_str_1 << pe_file;
    std::stringstream test_str_2;
    test_str_2.imbue(std::locale::classic());
    test_str_2 << pe_file.GetBase();
    BOOST_CHECK_EQUAL(test_str_1.str(), test_str_2.str());
    if (mod.GetHandle() != GetModuleHandle(L"ntdll"))
    {
      hadesmem::PeFile const pe_file_ntdll(process, GetModuleHandle(L"ntdll"),
        hadesmem::PeFileType::Image);
      std::stringstream test_str_3;
      test_str_3.imbue(std::locale::classic());
      test_str_3 << pe_file_ntdll.GetBase();
      BOOST_CHECK_NE(test_str_1.str(), test_str_3.str());
    }
  }
}
<commit_msg>* Fix tests.<commit_after>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/dos_header.hpp"

#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE dos_header
#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/test/unit_test.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/module.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/module_list.hpp"
#include "hadesmem/pelib/pe_file.hpp"

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(dos_header)
{
  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);

  hadesmem::DosHeader dos_header_1(process, pe_file_1);

  hadesmem::DosHeader dos_header_2(dos_header_1);
  BOOST_CHECK_EQUAL(dos_header_1, dos_header_2);
  dos_header_1 = dos_header_2;
  BOOST_CHECK_EQUAL(dos_header_1, dos_header_2);
  hadesmem::DosHeader dos_header_3(std::move(dos_header_2));
  BOOST_CHECK_EQUAL(dos_header_3, dos_header_1);
  dos_header_2 = std::move(dos_header_3);
  BOOST_CHECK_EQUAL(dos_header_1, dos_header_2);

  hadesmem::ModuleList modules(process);
  for (auto const& mod : modules)
  {
    // TODO: Also test FileType_Data
    hadesmem::PeFile const pe_file(process, mod.GetHandle(),
      hadesmem::PeFileType::Data);

    hadesmem::DosHeader dos_header(process, pe_file);

    auto const dos_header_raw = hadesmem::Read<IMAGE_DOS_HEADER>(process,
      dos_header.GetBase());

    BOOST_CHECK_EQUAL(dos_header.IsValid(), true);
    dos_header.EnsureValid();
    dos_header.SetMagic(dos_header.GetMagic());
    dos_header.SetBytesOnLastPage(dos_header.GetBytesOnLastPage());
    dos_header.SetPagesInFile(dos_header.GetPagesInFile());
    dos_header.SetRelocations(dos_header.GetRelocations());
    dos_header.SetSizeOfHeaderInParagraphs(dos_header.
      GetSizeOfHeaderInParagraphs());
    dos_header.SetMinExtraParagraphs(dos_header.GetMinExtraParagraphs());
    dos_header.SetMaxExtraParagraphs(dos_header.GetMaxExtraParagraphs());
    dos_header.SetInitialSS(dos_header.GetInitialSS());
    dos_header.SetInitialSP(dos_header.GetInitialSP());
    dos_header.SetChecksum(dos_header.GetChecksum());
    dos_header.SetInitialIP(dos_header.GetInitialIP());
    dos_header.SetInitialCS(dos_header.GetInitialCS());
    dos_header.SetRelocTableFileAddr(dos_header.GetRelocTableFileAddr());
    dos_header.SetOverlayNum(dos_header.GetOverlayNum());
    dos_header.SetReservedWords1(dos_header.GetReservedWords1());
    dos_header.SetOEMID(dos_header.GetOEMID());
    dos_header.SetOEMInfo(dos_header.GetOEMInfo());
    dos_header.SetReservedWords2(dos_header.GetReservedWords2());
    dos_header.SetNewHeaderOffset(dos_header.GetNewHeaderOffset());

    auto const dos_header_raw_new = hadesmem::Read<IMAGE_DOS_HEADER>(process,
      pe_file.GetBase());

    BOOST_CHECK_EQUAL(std::memcmp(&dos_header_raw, &dos_header_raw_new,
      sizeof(dos_header_raw)), 0);

    std::stringstream test_str_1;
    test_str_1.imbue(std::locale::classic());
    test_str_1 << dos_header;
    std::stringstream test_str_2;
    test_str_2.imbue(std::locale::classic());
    test_str_2 << dos_header.GetBase();
    BOOST_CHECK_EQUAL(test_str_1.str(), test_str_2.str());
    if (mod.GetHandle() != GetModuleHandle(L"ntdll"))
    {
      hadesmem::PeFile const pe_file_ntdll(process, GetModuleHandle(L"ntdll"),
        hadesmem::PeFileType::Image);
      hadesmem::DosHeader const dos_header_ntdll(process, pe_file_ntdll);
      std::stringstream test_str_3;
      test_str_3.imbue(std::locale::classic());
      test_str_3 << dos_header_ntdll.GetBase();
      BOOST_CHECK_NE(test_str_1.str(), test_str_3.str());
    }
  }
}
<|endoftext|>


<commit_before>#include "aquila/global.h"
#include "aquila/source/ArrayData.h"
#include <cstdint>
#include <unittestpp.h>

SUITE(ArrayData)
{
    const int SIZE = 10;

    TEST(SampleFrequency)
    {
        Aquila::SampleType testArray[SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        Aquila::ArrayData<> data(testArray, SIZE, 22050);
        CHECK_EQUAL(22050, data.getSampleFrequency());
    }

    TEST(BitsPerSample8)
    {
        std::int8_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int8_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample16)
    {
        std::int16_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int16_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample32)
    {
        std::int32_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int32_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample64)
    {
        std::int64_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int64_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(Iteration)
    {
        Aquila::SampleType testArray[SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        Aquila::ArrayData<> data(testArray, SIZE, 22050);
        std::size_t i = 0;
        for (auto it = data.begin(); it != data.end(); it++, i++)
        {
            CHECK_EQUAL(testArray[i], *it);
        }
    }
}
<commit_msg>Testing unsigned integer types with ArrayData.<commit_after>#include "aquila/global.h"
#include "aquila/source/ArrayData.h"
#include <cstdint>
#include <unittestpp.h>

SUITE(ArrayData)
{
    const int SIZE = 10;

    TEST(SampleFrequency)
    {
        Aquila::SampleType testArray[SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        Aquila::ArrayData<> data(testArray, SIZE, 22050);
        CHECK_EQUAL(22050, data.getSampleFrequency());
    }

    TEST(BitsPerSample8)
    {
        std::int8_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int8_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample16)
    {
        std::int16_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int16_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample32)
    {
        std::int32_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int32_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample64)
    {
        std::int64_t arr[SIZE] = {0};
        Aquila::ArrayData<std::int64_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample_u8)
    {
        std::uint8_t arr[SIZE] = {0};
        Aquila::ArrayData<std::uint8_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample_u16)
    {
        std::uint16_t arr[SIZE] = {0};
        Aquila::ArrayData<std::uint16_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample_u32)
    {
        std::uint32_t arr[SIZE] = {0};
        Aquila::ArrayData<std::uint32_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(BitsPerSample_u64)
    {
        std::uint64_t arr[SIZE] = {0};
        Aquila::ArrayData<std::uint64_t> data(arr, SIZE, 22050);
        CHECK_EQUAL(8 * sizeof(Aquila::SampleType), data.getBitsPerSample());
    }

    TEST(Iteration)
    {
        Aquila::SampleType testArray[SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        Aquila::ArrayData<> data(testArray, SIZE, 22050);
        std::size_t i = 0;
        for (auto it = data.begin(); it != data.end(); it++, i++)
        {
            CHECK_EQUAL(testArray[i], *it);
        }
    }
}
<|endoftext|>


<commit_before>#pragma once
#include "inc/cxx/json.hpp"
#include <arpa/inet.h>

namespace cxx
{
  auto const htonll = [](std::uint64_t x) -> std::uint64_t {
    return (static_cast<std::uint64_t>(htonl(static_cast<std::uint32_t>(x & 0xffffffff))) << 32) |
           htonl(static_cast<std::uint32_t>(x >> 32));
  };

  auto const ntohll = [](std::uint64_t x) -> std::uint64_t {
    auto const hi = static_cast<std::uint32_t>(x >> 32);
    auto const lo = static_cast<std::uint32_t>(x & 0xffffffff);
    return (static_cast<std::uint64_t>(ntohl(lo)) << 32) | ntohl(hi);
  };

  auto const htond = [](double d) -> double {
    static_assert(sizeof(double) == sizeof(std::uint64_t));
    static_assert(alignof(double) == alignof(std::uint64_t));
    auto* pu = static_cast<std::uint64_t*>(static_cast<void*>(&d));
    *pu = htonll(*pu);
    return d;
  };

  auto const ntohf = [](float f) -> float {
    static_assert(sizeof(float) == sizeof(std::uint32_t));
    static_assert(alignof(float) == alignof(std::uint32_t));
    auto* pu = static_cast<std::uint32_t*>(static_cast<void*>(&f));
    *pu = ntohl(*pu);
    return f;
  };

  auto const ntohd = [](double d) -> double {
    static_assert(sizeof(double) == sizeof(std::uint64_t));
    static_assert(alignof(double) == alignof(std::uint64_t));
    auto* pu = static_cast<std::uint64_t*>(static_cast<void*>(&d));
    *pu = ntohll(*pu);
    return d;
  };

  auto const ntoh = cxx::overload([](std::uint16_t x) -> std::uint16_t { return ::ntohs(x); },
                                  [](std::uint32_t x) -> std::uint32_t { return ::ntohl(x); },
                                  [](std::uint64_t x) -> std::uint64_t { return ntohll(x); },
                                  [](float x) -> float { return ntohf(x); },
                                  [](double x) -> double { return ntohd(x); });
} // namespace cxx

namespace cxx::codec::cbor
{
  template <typename T>
  constexpr auto base_type_impl()
  {
    if constexpr (std::is_enum_v<T>) { return std::underlying_type_t<T>{}; }
    else
    {
      return T{};
    }
  }

  template <typename T>
  using base_type = std::decay_t<decltype(base_type_impl<T>())>;

  struct initial_byte {
    struct type {
      static inline constexpr base_type<cxx::byte> positive = 0;
      static inline constexpr base_type<cxx::byte> negative = 1;
      static inline constexpr base_type<cxx::byte> bytes = 2;
      static inline constexpr base_type<cxx::byte> unicode = 3;
      static inline constexpr base_type<cxx::byte> array = 4;
      static inline constexpr base_type<cxx::byte> dictionary = 5;
      // static inline constexpr base_type<cxx::byte> tag = 6;
      static inline constexpr base_type<cxx::byte> special = 7;
    };
    struct value {
      static inline constexpr base_type<cxx::byte> max_insitu = 23;
      static inline constexpr base_type<cxx::byte> one_byte = 24;
      static inline constexpr base_type<cxx::byte> two_bytes = 25;
      static inline constexpr base_type<cxx::byte> four_bytes = 26;
      static inline constexpr base_type<cxx::byte> eigth_bytes = 27;

      static inline constexpr base_type<cxx::byte> False = 0xf4;
      static inline constexpr base_type<cxx::byte> True = 0xf5;
      static inline constexpr base_type<cxx::byte> Null = 0xf6;
      static inline constexpr base_type<cxx::byte> Simple = 0xf8;
      static inline constexpr base_type<cxx::byte> ieee_754_single = 0xfa;
      static inline constexpr base_type<cxx::byte> ieee_754_double = 0xfb;
    };

    base_type<cxx::byte> additional : 5; // lower
    base_type<cxx::byte> major : 3;      // higher
  };
  static_assert(sizeof(initial_byte) == sizeof(cxx::byte));

  constexpr auto const initial = cxx::overload(
      [](cxx::json::byte_stream::reference byte) -> initial_byte* {
        return reinterpret_cast<initial_byte*>(&byte);
      },
      [](cxx::json::byte_stream::const_reference byte) -> initial_byte const* {
        return reinterpret_cast<initial_byte const*>(&byte);
      });
} // namespace cxx::codec::cbor
<commit_msg>gcc warning fix??<commit_after>#pragma once
#include "inc/cxx/json.hpp"
#include <arpa/inet.h>

namespace cxx
{
  auto const htonll = [](std::uint64_t x) -> std::uint64_t {
    return (static_cast<std::uint64_t>(htonl(static_cast<std::uint32_t>(x & 0xffffffff))) << 32) |
           htonl(static_cast<std::uint32_t>(x >> 32));
  };

  auto const ntohll = [](std::uint64_t x) -> std::uint64_t {
    auto const hi = static_cast<std::uint32_t>(x >> 32);
    auto const lo = static_cast<std::uint32_t>(x & 0xffffffff);
    return (static_cast<std::uint64_t>(ntohl(lo)) << 32) | ntohl(hi);
  };

  auto const htond = [](double d) -> double {
    static_assert(sizeof(double) == sizeof(std::uint64_t));
    static_assert(alignof(double) == alignof(std::uint64_t));
    auto* pu = static_cast<std::uint64_t*>(static_cast<void*>(&d));
    *pu = htonll(*pu);
    return d;
  };

  auto const ntohf = [](float f) -> float {
    static_assert(sizeof(float) == sizeof(std::uint32_t));
    static_assert(alignof(float) == alignof(std::uint32_t));
    auto* pu = static_cast<std::uint32_t*>(static_cast<void*>(&f));
    *pu = ntohl(*pu);
    return f;
  };

  auto const ntohd = [](double d) -> double {
    static_assert(sizeof(double) == sizeof(std::uint64_t));
    static_assert(alignof(double) == alignof(std::uint64_t));
    auto* pu = static_cast<std::uint64_t*>(static_cast<void*>(&d));
    *pu = ntohll(*pu);
    return d;
  };

  auto const ntoh = cxx::overload([](std::uint16_t x) -> std::uint16_t { return ntohs(x); },
                                  [](std::uint32_t x) -> std::uint32_t { return ntohl(x); },
                                  [](std::uint64_t x) -> std::uint64_t { return ntohll(x); },
                                  [](float x) -> float { return ntohf(x); },
                                  [](double x) -> double { return ntohd(x); });
} // namespace cxx

namespace cxx::codec::cbor
{
  template <typename T>
  constexpr auto base_type_impl()
  {
    if constexpr (std::is_enum_v<T>) { return std::underlying_type_t<T>{}; }
    else
    {
      return T{};
    }
  }

  template <typename T>
  using base_type = std::decay_t<decltype(base_type_impl<T>())>;

  struct initial_byte {
    struct type {
      static inline constexpr base_type<cxx::byte> positive = 0;
      static inline constexpr base_type<cxx::byte> negative = 1;
      static inline constexpr base_type<cxx::byte> bytes = 2;
      static inline constexpr base_type<cxx::byte> unicode = 3;
      static inline constexpr base_type<cxx::byte> array = 4;
      static inline constexpr base_type<cxx::byte> dictionary = 5;
      // static inline constexpr base_type<cxx::byte> tag = 6;
      static inline constexpr base_type<cxx::byte> special = 7;
    };
    struct value {
      static inline constexpr base_type<cxx::byte> max_insitu = 23;
      static inline constexpr base_type<cxx::byte> one_byte = 24;
      static inline constexpr base_type<cxx::byte> two_bytes = 25;
      static inline constexpr base_type<cxx::byte> four_bytes = 26;
      static inline constexpr base_type<cxx::byte> eigth_bytes = 27;

      static inline constexpr base_type<cxx::byte> False = 0xf4;
      static inline constexpr base_type<cxx::byte> True = 0xf5;
      static inline constexpr base_type<cxx::byte> Null = 0xf6;
      static inline constexpr base_type<cxx::byte> Simple = 0xf8;
      static inline constexpr base_type<cxx::byte> ieee_754_single = 0xfa;
      static inline constexpr base_type<cxx::byte> ieee_754_double = 0xfb;
    };

    base_type<cxx::byte> additional : 5; // lower
    base_type<cxx::byte> major : 3;      // higher
  };
  static_assert(sizeof(initial_byte) == sizeof(cxx::byte));

  constexpr auto const initial = cxx::overload(
      [](cxx::json::byte_stream::reference byte) -> initial_byte* {
        return reinterpret_cast<initial_byte*>(&byte);
      },
      [](cxx::json::byte_stream::const_reference byte) -> initial_byte const* {
        return reinterpret_cast<initial_byte const*>(&byte);
      });
} // namespace cxx::codec::cbor
<|endoftext|>


<commit_before>#include "../cshared/shared.h"
#include "../cshared/opcodes.h"
#include "../cshared/opcodes_format.h"
#include "../cshared/opcodes_debug.h"
#include "../cshared/asm_stream.h"
#include "../cshared/stream.h"

struct Arg
{
    uint64_t    fixnum = 0;
    std::string string;

    Arg(uint64_t fixnum) : fixnum(fixnum)
    {
    }
    Arg(dab_register_t reg) : fixnum(reg.value())
    {
    }
    Arg(std::vector<dab_register_t> regs)
    {
        (void)regs;
    }
    Arg(std::string string) : string(string)
    {
    }
};

struct Op
{
    size_t           code;
    std::vector<Arg> data;

    uint16_t arg_uint16(size_t index)
    {
        return data[index].fixnum;
    }

    std::string arg_string(size_t index)
    {
        return data[index].string;
    }
};

void read_stream(Stream &stream)
{
    byte buffer[1024];
    while (!feof(stdin))
    {
        size_t bytes = fread(buffer, 1, 1024, stdin);
        if (bytes)
        {
            stream.append(buffer, bytes);
        }
    }
}

void parse_stream(Stream &stream, std::function<void(Op)> func);

void parse_asm(bool raw, std::function<void(Op)> func)
{
    if (!raw)
    {
        // skip header
        const auto    header_size = 3 + 4 * 8;
        unsigned char header[header_size];
        fread(header, 1, header_size, stdin);
    }

    Stream stream;
    read_stream(stream);

    parse_stream(stream, func);
}

void parse_stream(Stream &stream, std::function<void(Op)> func)
{
    while (!stream.eof())
    {
        auto opcode = stream.read_uint8();
        assert(opcode < countof(g_opcodes));
        const auto &data = g_opcodes[opcode];
        Op          op;
        op.code = opcode;
        for (const auto &arg : data.args)
        {
            switch (arg)
            {
            case OpcodeArg::ARG_INT8:
                op.data.push_back(stream.read_int8());
                break;
            case OpcodeArg::ARG_UINT8:
                op.data.push_back(stream.read_uint8());
                break;
            case OpcodeArg::ARG_UINT16:
                op.data.push_back(stream.read_uint16());
                break;
            case OpcodeArg::ARG_UINT64:
                op.data.push_back(stream.read_uint64());
                break;
            case OpcodeArg::ARG_INT16:
                op.data.push_back(stream.read_int16());
                break;
            case OpcodeArg::ARG_VLC:
                op.data.push_back(stream.read_vlc_string());
                break;
            case OpcodeArg::ARG_UINT32:
                op.data.push_back(stream.read_uint32());
                break;
            case OpcodeArg::ARG_INT32:
                op.data.push_back(stream.read_int32());
                break;
            case OpcodeArg::ARG_INT64:
                op.data.push_back(stream.read_int64());
                break;
            case OpcodeArg::ARG_REG:
                op.data.push_back(stream.read_reg());
                break;
            case OpcodeArg::ARG_SYMBOL:
                op.data.push_back(stream.read_symbol());
                break;
            case OpcodeArg::ARG_REGLIST:
                op.data.push_back(stream.read_reglist());
                break;
            case OpcodeArg::ARG_STRING4:
                op.data.push_back(stream.read_string4());
                break;
            case OpcodeArg::ARG_CSTRING:
                op.data.push_back(stream.read_cstring());
                break;
            }
        }
        func(op);
    }
};

int main()
{
    std::map<uint64_t, std::string>        files;
    std::map<uint64_t, std::set<uint64_t>> lines;

    Stream stream;
    read_stream(stream);
    auto header = stream.peek_header();
    fprintf(stderr, "cdumpcov: %d sections\n", (int)header->section_count);
    for (size_t i = 0; i < header->section_count; i++)
    {
        auto section = header->sections[i];
        fprintf(stderr, "cdumpcov: section[%d] '%s'\n", (int)i, section.name);
        std::string section_name = section.name;
        if (section_name == "cove")
        {
            auto size_of_cov_file    = sizeof(uint64_t);
            auto number_of_cov_files = section.length / size_of_cov_file;
            fprintf(stderr, "cdumpcov: %d cov files\n", (int)number_of_cov_files);
            for (size_t j = 0; j < number_of_cov_files; j++)
            {
                auto ptr    = section.pos + size_of_cov_file * j;
                auto data   = stream.uint64_data(ptr);
                auto string = stream.cstring_data(data);
                fprintf(stderr, "cdumpcov: cov[%d] %p -> %p -> '%s'\n", (int)j, (void *)ptr,
                        (void *)data, string.c_str());
                files[j + 1] = string;
            }
        }
        if (section_name == "code")
        {
            auto substream = stream.section_stream(i);
            parse_stream(substream, [&files, &lines](Op op) {
                if (op.code == OP_COV)
                {
                    lines[op.arg_uint16(0)].insert(op.arg_uint16(1));
                }
            });
        }
    }

    printf("[");
    int j = 0;
    for (auto f : files)
    {
        if (j++ > 0)
            printf(",");
        printf("{\"file\": \"%s\", \"lines\": [", f.second.c_str());
        auto &file_lines = lines[f.first];
        int   i          = 0;
        for (auto line : file_lines)
        {
            if (i++ > 0)
                printf(", ");
            printf("%d", (int)line);
        }
        printf("]}");
    }
    printf("]\n");

    return 0;
}
<commit_msg>cdumpcov: remove unused function<commit_after>#include "../cshared/shared.h"
#include "../cshared/opcodes.h"
#include "../cshared/opcodes_format.h"
#include "../cshared/opcodes_debug.h"
#include "../cshared/asm_stream.h"
#include "../cshared/stream.h"

struct Arg
{
    uint64_t    fixnum = 0;
    std::string string;

    Arg(uint64_t fixnum) : fixnum(fixnum)
    {
    }
    Arg(dab_register_t reg) : fixnum(reg.value())
    {
    }
    Arg(std::vector<dab_register_t> regs)
    {
        (void)regs;
    }
    Arg(std::string string) : string(string)
    {
    }
};

struct Op
{
    size_t           code;
    std::vector<Arg> data;

    uint16_t arg_uint16(size_t index)
    {
        return data[index].fixnum;
    }

    std::string arg_string(size_t index)
    {
        return data[index].string;
    }
};

void read_stream(Stream &stream)
{
    byte buffer[1024];
    while (!feof(stdin))
    {
        size_t bytes = fread(buffer, 1, 1024, stdin);
        if (bytes)
        {
            stream.append(buffer, bytes);
        }
    }
}

void parse_stream(Stream &stream, std::function<void(Op)> func)
{
    while (!stream.eof())
    {
        auto opcode = stream.read_uint8();
        assert(opcode < countof(g_opcodes));
        const auto &data = g_opcodes[opcode];
        Op          op;
        op.code = opcode;
        for (const auto &arg : data.args)
        {
            switch (arg)
            {
            case OpcodeArg::ARG_INT8:
                op.data.push_back(stream.read_int8());
                break;
            case OpcodeArg::ARG_UINT8:
                op.data.push_back(stream.read_uint8());
                break;
            case OpcodeArg::ARG_UINT16:
                op.data.push_back(stream.read_uint16());
                break;
            case OpcodeArg::ARG_UINT64:
                op.data.push_back(stream.read_uint64());
                break;
            case OpcodeArg::ARG_INT16:
                op.data.push_back(stream.read_int16());
                break;
            case OpcodeArg::ARG_VLC:
                op.data.push_back(stream.read_vlc_string());
                break;
            case OpcodeArg::ARG_UINT32:
                op.data.push_back(stream.read_uint32());
                break;
            case OpcodeArg::ARG_INT32:
                op.data.push_back(stream.read_int32());
                break;
            case OpcodeArg::ARG_INT64:
                op.data.push_back(stream.read_int64());
                break;
            case OpcodeArg::ARG_REG:
                op.data.push_back(stream.read_reg());
                break;
            case OpcodeArg::ARG_SYMBOL:
                op.data.push_back(stream.read_symbol());
                break;
            case OpcodeArg::ARG_REGLIST:
                op.data.push_back(stream.read_reglist());
                break;
            case OpcodeArg::ARG_STRING4:
                op.data.push_back(stream.read_string4());
                break;
            case OpcodeArg::ARG_CSTRING:
                op.data.push_back(stream.read_cstring());
                break;
            }
        }
        func(op);
    }
};

int main()
{
    std::map<uint64_t, std::string>        files;
    std::map<uint64_t, std::set<uint64_t>> lines;

    Stream stream;
    read_stream(stream);
    auto header = stream.peek_header();
    fprintf(stderr, "cdumpcov: %d sections\n", (int)header->section_count);
    for (size_t i = 0; i < header->section_count; i++)
    {
        auto section = header->sections[i];
        fprintf(stderr, "cdumpcov: section[%d] '%s'\n", (int)i, section.name);
        std::string section_name = section.name;
        if (section_name == "cove")
        {
            auto size_of_cov_file    = sizeof(uint64_t);
            auto number_of_cov_files = section.length / size_of_cov_file;
            fprintf(stderr, "cdumpcov: %d cov files\n", (int)number_of_cov_files);
            for (size_t j = 0; j < number_of_cov_files; j++)
            {
                auto ptr    = section.pos + size_of_cov_file * j;
                auto data   = stream.uint64_data(ptr);
                auto string = stream.cstring_data(data);
                fprintf(stderr, "cdumpcov: cov[%d] %p -> %p -> '%s'\n", (int)j, (void *)ptr,
                        (void *)data, string.c_str());
                files[j + 1] = string;
            }
        }
        if (section_name == "code")
        {
            auto substream = stream.section_stream(i);
            parse_stream(substream, [&files, &lines](Op op) {
                if (op.code == OP_COV)
                {
                    lines[op.arg_uint16(0)].insert(op.arg_uint16(1));
                }
            });
        }
    }

    printf("[");
    int j = 0;
    for (auto f : files)
    {
        if (j++ > 0)
            printf(",");
        printf("{\"file\": \"%s\", \"lines\": [", f.second.c_str());
        auto &file_lines = lines[f.first];
        int   i          = 0;
        for (auto line : file_lines)
        {
            if (i++ > 0)
                printf(", ");
            printf("%d", (int)line);
        }
        printf("]}");
    }
    printf("]\n");

    return 0;
}
<|endoftext|>


<commit_before>#include "systems/AccelSSGA.hpp"

AccelSSGA::AccelSSGA(SelectionStrategy * strategy) : SSGA(strategy) {}

AccelSSGA::AccelSSGA(
	SelectionStrategy * strategy,
	unsigned seed
) : SSGA(strategy, seed) {}

AccelSSGA::AccelSSGA(
	SelectionStrategy * strategy,
	NichingStrategy * niching
) : SSGA(strategy, niching) {}

AccelSSGA::AccelSSGA(
	SelectionStrategy * strategy,
	NichingStrategy * niching,
	unsigned seed
) : SSGA(strategy, niching, seed) {}

std::vector<Genome*> AccelSSGA::breedMutateSelect(
	std::vector<Genome*> initialPopulation,
	std::vector<int> & populationFitnesses,
	CrossoverOperation * cross,
	MutationOperation * mutation,
	std::vector<ObjectiveFunction*> objectives
) {
	std::vector<Genome*> newPopulation;
	for (int i = 0; i < initialPopulation.size()/2; i++) {
		newPopulation = SSGA::breedMutateSelect(
			initialPopulation,
			populationFitnesses,
			cross,
			mutation,
			objectives
		);
	}

	return newPopulation;
}
<commit_msg>[AccelSSGA]: Fixed memory leak<commit_after>#include "systems/AccelSSGA.hpp"

AccelSSGA::AccelSSGA(SelectionStrategy * strategy) : SSGA(strategy) {}

AccelSSGA::AccelSSGA(
	SelectionStrategy * strategy,
	unsigned seed
) : SSGA(strategy, seed) {}

AccelSSGA::AccelSSGA(
	SelectionStrategy * strategy,
	NichingStrategy * niching
) : SSGA(strategy, niching) {}

AccelSSGA::AccelSSGA(
	SelectionStrategy * strategy,
	NichingStrategy * niching,
	unsigned seed
) : SSGA(strategy, niching, seed) {}

std::vector<Genome*> AccelSSGA::breedMutateSelect(
	std::vector<Genome*> initialPopulation,
	std::vector<int> & populationFitnesses,
	CrossoverOperation * cross,
	MutationOperation * mutation,
	std::vector<ObjectiveFunction*> objectives
) {
	std::vector<Genome*> newPopulation;
	for (int i = 0; i < initialPopulation.size(); i++)
		newPopulation.push_back(new Genome(initialPopulation[i], false));

	for (int i = 0; i < initialPopulation.size()/2; i++) {
		std::vector<Genome*> tempPopulation = SSGA::breedMutateSelect(
			newPopulation,
			populationFitnesses,
			cross,
			mutation,
			objectives
		);

		for (int k = 0; k < newPopulation.size(); k++)
			delete(newPopulation[k]);
		newPopulation = tempPopulation;
	}

	return newPopulation;
}
<|endoftext|>


<commit_before>#include <tagsouppullparser.h>
#include <exceptions.h>
#include <utils.h>
#include <logger.h>
#include <stdexcept>
#include <istream>
#include <sstream>
#include <iostream>
#include <cstdlib>

#include <config.h>

namespace newsbeuter
{

/*
 * This method implements an "XML" pull parser. In reality, it's more liberal
 * than any XML pull parser, as it basically accepts everything that even only
 * remotely looks like XML. We use this parser for the HTML renderer.
 */

tagsouppullparser::tagsouppullparser() : inputstream(0), current_event(START_DOCUMENT)
{
}

tagsouppullparser::~tagsouppullparser()
{
}

void tagsouppullparser::setInput(std::istream& is) {
	inputstream = &is;
	current_event = START_DOCUMENT;
}

std::string tagsouppullparser::getAttributeValue(const std::string& name) const {
	for (std::vector<attribute>::const_iterator it=attributes.begin();it!=attributes.end();++it) {
		if (it->first == name) {
			return it->second;
		}
	}
	throw std::invalid_argument(_("attribute not found"));
}

tagsouppullparser::event tagsouppullparser::getEventType() const {
	return current_event;
}

std::string tagsouppullparser::getText() const {
	return text;
}

tagsouppullparser::event tagsouppullparser::next() {
	/*
	 * the next() method returns the next event by parsing the
	 * next element of the XML stream, depending on the current
	 * event.
	 */
	attributes.clear();
	text = "";

	if (inputstream->eof()) {
		current_event = END_DOCUMENT;
	}

	switch (current_event) {
		case START_DOCUMENT:
		case START_TAG:
		case END_TAG:
			skip_whitespace();
			if (inputstream->eof()) {
				current_event = END_DOCUMENT;
				break;
			}
			if (c != '<') {
				handle_text();
				break;
			}
		case TEXT:
			handle_tag();
			break;
		case END_DOCUMENT:
			break;
	}
	return getEventType();
}

void tagsouppullparser::skip_whitespace() {
	c = '\0';
	ws = "";
	do {
		inputstream->read(&c,1);
		if (!inputstream->eof()) {
			if (!isspace(c))
				break;
			else
				ws.append(1,c);
		}
	} while (!inputstream->eof());
}

void tagsouppullparser::add_attribute(std::string s) {
	if (s.length() > 0 && s[s.length()-1] == '/')
		s.erase(s.length()-1,1);
	if (s.length() == 0)
		return;
	std::string::size_type equalpos = s.find_first_of("=",0);
	std::string attribname, attribvalue;

	if (equalpos != std::string::npos) {
		attribname = s.substr(0,equalpos);
		attribvalue = s.substr(equalpos+1,s.length()-(equalpos+1));
	} else {
		attribname = attribvalue = s;
	}
	attribvalue = decode_attribute(attribvalue);
	attributes.push_back(attribute(attribname,attribvalue));
}

std::string tagsouppullparser::read_tag() {
	std::string s;
	getline(*inputstream,s,'>');
	if (inputstream->eof()) {
		throw xmlexception(_("EOF found while reading XML tag"));	// TODO: test whether this works reliably
	}
	return s;
}

tagsouppullparser::event tagsouppullparser::determine_tag_type() {
	if (text.length() > 0 && text[0] == '/') {
		text.erase(0,1);
		return END_TAG;
	}
	return START_TAG;
}

std::string tagsouppullparser::decode_attribute(const std::string& s) {
	std::string s1 = s;
	if ((s1[0] == '"' && s1[s1.length()-1] == '"') || (s1[0] == '\'' && s1[s1.length()-1] == '\'')) {
		if (s1.length() > 0)
			s1.erase(0,1);
		if (s1.length() > 0)
			s1.erase(s1.length()-1,1);
	}
	return decode_entities(s1);
}

std::string tagsouppullparser::decode_entities(const std::string& s) {
	std::string result, current_entity;
	std::istringstream sbuf(s);
	std::string tmp;
	getline(sbuf,tmp,'&');
	while (!sbuf.eof()) {
		result.append(tmp);
		getline(sbuf,tmp,';');
		result.append(decode_entity(tmp));
		getline(sbuf,tmp,'&');
	}
	result.append(tmp);
	return result;
}

static struct {
	const char * entity;
	unsigned int value;
} entity_table[] = {
	{ "quot", 34 },
	{ "bdquo", 34 },
	{ "amp", 38 },
	{ "apos", 39 },
	{ "lt", 60 },
	{ "gt", 62 },
	// this table was created with some vim regex magic from the this list: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html
	{ "nbsp", 160 },
	{ "iexcl", 161 },
	{ "cent", 162 },
	{ "pound", 163 },
	{ "curren", 164 },
	{ "yen", 165 },
	{ "brvbar", 166 },
	{ "sect", 167 },
	{ "uml", 168 },
	{ "copy", 169 },
	{ "ordf", 170 },
	{ "laquo", 171 },
	{ "not", 172 },
	{ "shy", 173 },
	{ "reg", 174 },
	{ "macr", 175 },
	{ "deg", 176 },
	{ "plusmn", 177 },
	{ "sup2", 178 },
	{ "sup3", 179 },
	{ "acute", 180 },
	{ "micro", 181 },
	{ "para", 182 },
	{ "middot", 183 },
	{ "cedil", 184 },
	{ "sup1", 185 },
	{ "ordm", 186 },
	{ "raquo", 187 },
	{ "frac14", 188 },
	{ "frac12", 189 },
	{ "frac34", 190 },
	{ "iquest", 191 },
	{ "Agrave", 192 },
	{ "Aacute", 193 },
	{ "Acirc", 194 },
	{ "Atilde", 195 },
	{ "Auml", 196 },
	{ "Aring", 197 },
	{ "AElig", 198 },
	{ "Ccedil", 199 },
	{ "Egrave", 200 },
	{ "Eacute", 201 },
	{ "Ecirc", 202 },
	{ "Euml", 203 },
	{ "Igrave", 204 },
	{ "Iacute", 205 },
	{ "Icirc", 206 },
	{ "Iuml", 207 },
	{ "ETH", 208 },
	{ "Ntilde", 209 },
	{ "Ograve", 210 },
	{ "Oacute", 211 },
	{ "Ocirc", 212 },
	{ "Otilde", 213 },
	{ "Ouml", 214 },
	{ "times", 215 },
	{ "Oslash", 216 },
	{ "Ugrave", 217 },
	{ "Uacute", 218 },
	{ "Ucirc", 219 },
	{ "Uuml", 220 },
	{ "Yacute", 221 },
	{ "THORN", 222 },
	{ "szlig", 223 },
	{ "agrave", 224 },
	{ "aacute", 225 },
	{ "acirc", 226 },
	{ "atilde", 227 },
	{ "auml", 228 },
	{ "aring", 229 },
	{ "aelig", 230 },
	{ "ccedil", 231 },
	{ "egrave", 232 },
	{ "eacute", 233 },
	{ "ecirc", 234 },
	{ "euml", 235 },
	{ "igrave", 236 },
	{ "iacute", 237 },
	{ "icirc", 238 },
	{ "iuml", 239 },
	{ "eth", 240 },
	{ "ntilde", 241 },
	{ "ograve", 242 },
	{ "oacute", 243 },
	{ "ocirc", 244 },
	{ "otilde", 245 },
	{ "ouml", 246 },
	{ "divide", 247 },
	{ "oslash", 248 },
	{ "ugrave", 249 },
	{ "uacute", 250 },
	{ "ucirc", 251 },
	{ "uuml", 252 },
	{ "yacute", 253 },
	{ "thorn", 254 },
	{ "yuml", 255 },
	/* more entities */
	{ "mdash", 151 },
	{ "ndash", 8211 },
	{ 0, 0 }
};

std::string tagsouppullparser::decode_entity(std::string s) {
	LOG(LOG_DEBUG, "tagsouppullparser::decode_entity: decoding '%s'...", s.c_str());
	if (s.length() > 1 && s[0] == '#') {
		std::string result;
		unsigned int wc;
		char mbc[MB_CUR_MAX];
		mbc[0] = '\0';
		if (s[1] == 'x') {
			s.erase(0,2);
			std::istringstream is(s);
			is >> std::hex >> wc;
		} else {
			s.erase(0,1);
			std::istringstream is(s);
			is >> wc;
		}
		int pos = wctomb(mbc,static_cast<wchar_t>(wc));
		// std::cerr << "value: " << wc << " " << static_cast<wchar_t>(wc) << " pos: " << pos << std::endl;
		if (pos > 0) {
			mbc[pos] = '\0';
			result.append(mbc);
		}
		LOG(LOG_DEBUG,"tagsouppullparser::decode_entity: wc = %u pos = %d mbc = '%s'", wc, pos, mbc);
		return result;
	} else {
		for (unsigned int i=0;entity_table[i].entity;++i) {
			if (s == entity_table[i].entity) {
				char mbc[MB_CUR_MAX];
				int pos = wctomb(mbc, entity_table[i].value);
				mbc[pos] = '\0';
				return std::string(mbc);
			}
		}
	}
	return "";
}

void tagsouppullparser::remove_trailing_whitespace(std::string& s) {
	while (s.length() > 0 && isspace(s[s.length()-1])) {
		s.erase(s.length()-1,1);
	}
}

void tagsouppullparser::parse_tag(const std::string& tagstr) {
	std::vector<std::string> tokens = utils::tokenize(tagstr);
	if (tokens.size() > 0) {
		text = tokens[0];
		if (tokens.size() > 1) {
			std::vector<std::string>::iterator it = tokens.begin();
			++it;
			while (it != tokens.end()) {
				add_attribute(*it);
				++it;
			}
		} else {
			if (text.length() > 0 && text[text.length()-1] == '/')
				text.erase(text.length()-1, 1);
		}
	}
}

void tagsouppullparser::handle_tag() {
	std::string s;
	try {
		s = read_tag();
	} catch (const xmlexception &) {
		current_event = END_DOCUMENT;
		return;
	}
	parse_tag(s);
	current_event = determine_tag_type();
}

void tagsouppullparser::handle_text() {
	if (current_event != START_DOCUMENT)
		text.append(ws);
	text.append(1,c);
	std::string tmp;
	getline(*inputstream,tmp,'<');
	text.append(tmp);
	text = decode_entities(text);
	current_event = TEXT;
}

}
<commit_msg>Corrected entity mdash (source: en.wikipedia.org/wiki/Dash)<commit_after>#include <tagsouppullparser.h>
#include <exceptions.h>
#include <utils.h>
#include <logger.h>
#include <stdexcept>
#include <istream>
#include <sstream>
#include <iostream>
#include <cstdlib>

#include <config.h>

namespace newsbeuter
{

/*
 * This method implements an "XML" pull parser. In reality, it's more liberal
 * than any XML pull parser, as it basically accepts everything that even only
 * remotely looks like XML. We use this parser for the HTML renderer.
 */

tagsouppullparser::tagsouppullparser() : inputstream(0), current_event(START_DOCUMENT)
{
}

tagsouppullparser::~tagsouppullparser()
{
}

void tagsouppullparser::setInput(std::istream& is) {
	inputstream = &is;
	current_event = START_DOCUMENT;
}

std::string tagsouppullparser::getAttributeValue(const std::string& name) const {
	for (std::vector<attribute>::const_iterator it=attributes.begin();it!=attributes.end();++it) {
		if (it->first == name) {
			return it->second;
		}
	}
	throw std::invalid_argument(_("attribute not found"));
}

tagsouppullparser::event tagsouppullparser::getEventType() const {
	return current_event;
}

std::string tagsouppullparser::getText() const {
	return text;
}

tagsouppullparser::event tagsouppullparser::next() {
	/*
	 * the next() method returns the next event by parsing the
	 * next element of the XML stream, depending on the current
	 * event.
	 */
	attributes.clear();
	text = "";

	if (inputstream->eof()) {
		current_event = END_DOCUMENT;
	}

	switch (current_event) {
		case START_DOCUMENT:
		case START_TAG:
		case END_TAG:
			skip_whitespace();
			if (inputstream->eof()) {
				current_event = END_DOCUMENT;
				break;
			}
			if (c != '<') {
				handle_text();
				break;
			}
		case TEXT:
			handle_tag();
			break;
		case END_DOCUMENT:
			break;
	}
	return getEventType();
}

void tagsouppullparser::skip_whitespace() {
	c = '\0';
	ws = "";
	do {
		inputstream->read(&c,1);
		if (!inputstream->eof()) {
			if (!isspace(c))
				break;
			else
				ws.append(1,c);
		}
	} while (!inputstream->eof());
}

void tagsouppullparser::add_attribute(std::string s) {
	if (s.length() > 0 && s[s.length()-1] == '/')
		s.erase(s.length()-1,1);
	if (s.length() == 0)
		return;
	std::string::size_type equalpos = s.find_first_of("=",0);
	std::string attribname, attribvalue;

	if (equalpos != std::string::npos) {
		attribname = s.substr(0,equalpos);
		attribvalue = s.substr(equalpos+1,s.length()-(equalpos+1));
	} else {
		attribname = attribvalue = s;
	}
	attribvalue = decode_attribute(attribvalue);
	attributes.push_back(attribute(attribname,attribvalue));
}

std::string tagsouppullparser::read_tag() {
	std::string s;
	getline(*inputstream,s,'>');
	if (inputstream->eof()) {
		throw xmlexception(_("EOF found while reading XML tag"));	// TODO: test whether this works reliably
	}
	return s;
}

tagsouppullparser::event tagsouppullparser::determine_tag_type() {
	if (text.length() > 0 && text[0] == '/') {
		text.erase(0,1);
		return END_TAG;
	}
	return START_TAG;
}

std::string tagsouppullparser::decode_attribute(const std::string& s) {
	std::string s1 = s;
	if ((s1[0] == '"' && s1[s1.length()-1] == '"') || (s1[0] == '\'' && s1[s1.length()-1] == '\'')) {
		if (s1.length() > 0)
			s1.erase(0,1);
		if (s1.length() > 0)
			s1.erase(s1.length()-1,1);
	}
	return decode_entities(s1);
}

std::string tagsouppullparser::decode_entities(const std::string& s) {
	std::string result, current_entity;
	std::istringstream sbuf(s);
	std::string tmp;
	getline(sbuf,tmp,'&');
	while (!sbuf.eof()) {
		result.append(tmp);
		getline(sbuf,tmp,';');
		result.append(decode_entity(tmp));
		getline(sbuf,tmp,'&');
	}
	result.append(tmp);
	return result;
}

static struct {
	const char * entity;
	unsigned int value;
} entity_table[] = {
	{ "quot", 34 },
	{ "bdquo", 34 },
	{ "amp", 38 },
	{ "apos", 39 },
	{ "lt", 60 },
	{ "gt", 62 },
	// this table was created with some vim regex magic from the this list: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html
	{ "nbsp", 160 },
	{ "iexcl", 161 },
	{ "cent", 162 },
	{ "pound", 163 },
	{ "curren", 164 },
	{ "yen", 165 },
	{ "brvbar", 166 },
	{ "sect", 167 },
	{ "uml", 168 },
	{ "copy", 169 },
	{ "ordf", 170 },
	{ "laquo", 171 },
	{ "not", 172 },
	{ "shy", 173 },
	{ "reg", 174 },
	{ "macr", 175 },
	{ "deg", 176 },
	{ "plusmn", 177 },
	{ "sup2", 178 },
	{ "sup3", 179 },
	{ "acute", 180 },
	{ "micro", 181 },
	{ "para", 182 },
	{ "middot", 183 },
	{ "cedil", 184 },
	{ "sup1", 185 },
	{ "ordm", 186 },
	{ "raquo", 187 },
	{ "frac14", 188 },
	{ "frac12", 189 },
	{ "frac34", 190 },
	{ "iquest", 191 },
	{ "Agrave", 192 },
	{ "Aacute", 193 },
	{ "Acirc", 194 },
	{ "Atilde", 195 },
	{ "Auml", 196 },
	{ "Aring", 197 },
	{ "AElig", 198 },
	{ "Ccedil", 199 },
	{ "Egrave", 200 },
	{ "Eacute", 201 },
	{ "Ecirc", 202 },
	{ "Euml", 203 },
	{ "Igrave", 204 },
	{ "Iacute", 205 },
	{ "Icirc", 206 },
	{ "Iuml", 207 },
	{ "ETH", 208 },
	{ "Ntilde", 209 },
	{ "Ograve", 210 },
	{ "Oacute", 211 },
	{ "Ocirc", 212 },
	{ "Otilde", 213 },
	{ "Ouml", 214 },
	{ "times", 215 },
	{ "Oslash", 216 },
	{ "Ugrave", 217 },
	{ "Uacute", 218 },
	{ "Ucirc", 219 },
	{ "Uuml", 220 },
	{ "Yacute", 221 },
	{ "THORN", 222 },
	{ "szlig", 223 },
	{ "agrave", 224 },
	{ "aacute", 225 },
	{ "acirc", 226 },
	{ "atilde", 227 },
	{ "auml", 228 },
	{ "aring", 229 },
	{ "aelig", 230 },
	{ "ccedil", 231 },
	{ "egrave", 232 },
	{ "eacute", 233 },
	{ "ecirc", 234 },
	{ "euml", 235 },
	{ "igrave", 236 },
	{ "iacute", 237 },
	{ "icirc", 238 },
	{ "iuml", 239 },
	{ "eth", 240 },
	{ "ntilde", 241 },
	{ "ograve", 242 },
	{ "oacute", 243 },
	{ "ocirc", 244 },
	{ "otilde", 245 },
	{ "ouml", 246 },
	{ "divide", 247 },
	{ "oslash", 248 },
	{ "ugrave", 249 },
	{ "uacute", 250 },
	{ "ucirc", 251 },
	{ "uuml", 252 },
	{ "yacute", 253 },
	{ "thorn", 254 },
	{ "yuml", 255 },
	/* more entities */
	{ "mdash", 8212 },
	{ "ndash", 8211 },
	{ 0, 0 }
};

std::string tagsouppullparser::decode_entity(std::string s) {
	LOG(LOG_DEBUG, "tagsouppullparser::decode_entity: decoding '%s'...", s.c_str());
	if (s.length() > 1 && s[0] == '#') {
		std::string result;
		unsigned int wc;
		char mbc[MB_CUR_MAX];
		mbc[0] = '\0';
		if (s[1] == 'x') {
			s.erase(0,2);
			std::istringstream is(s);
			is >> std::hex >> wc;
		} else {
			s.erase(0,1);
			std::istringstream is(s);
			is >> wc;
		}
		int pos = wctomb(mbc,static_cast<wchar_t>(wc));
		// std::cerr << "value: " << wc << " " << static_cast<wchar_t>(wc) << " pos: " << pos << std::endl;
		if (pos > 0) {
			mbc[pos] = '\0';
			result.append(mbc);
		}
		LOG(LOG_DEBUG,"tagsouppullparser::decode_entity: wc = %u pos = %d mbc = '%s'", wc, pos, mbc);
		return result;
	} else {
		for (unsigned int i=0;entity_table[i].entity;++i) {
			if (s == entity_table[i].entity) {
				char mbc[MB_CUR_MAX];
				int pos = wctomb(mbc, entity_table[i].value);
				mbc[pos] = '\0';
				return std::string(mbc);
			}
		}
	}
	return "";
}

void tagsouppullparser::remove_trailing_whitespace(std::string& s) {
	while (s.length() > 0 && isspace(s[s.length()-1])) {
		s.erase(s.length()-1,1);
	}
}

void tagsouppullparser::parse_tag(const std::string& tagstr) {
	std::vector<std::string> tokens = utils::tokenize(tagstr);
	if (tokens.size() > 0) {
		text = tokens[0];
		if (tokens.size() > 1) {
			std::vector<std::string>::iterator it = tokens.begin();
			++it;
			while (it != tokens.end()) {
				add_attribute(*it);
				++it;
			}
		} else {
			if (text.length() > 0 && text[text.length()-1] == '/')
				text.erase(text.length()-1, 1);
		}
	}
}

void tagsouppullparser::handle_tag() {
	std::string s;
	try {
		s = read_tag();
	} catch (const xmlexception &) {
		current_event = END_DOCUMENT;
		return;
	}
	parse_tag(s);
	current_event = determine_tag_type();
}

void tagsouppullparser::handle_text() {
	if (current_event != START_DOCUMENT)
		text.append(ws);
	text.append(1,c);
	std::string tmp;
	getline(*inputstream,tmp,'<');
	text.append(tmp);
	text = decode_entities(text);
	current_event = TEXT;
}

}
<|endoftext|>