<commit_before>#include "http_server.hpp"
#include "exceptions.hpp"

#include <string.h>

using namespace std;

namespace httptth
{

//
// http_server
//
http_server::http_server(http_server::handler_type h) :
    handler(h),
    underlying_server(internal_handler(h))
{
    dprintf(logger::DEBUG, "http_server constructed");
}
/*
http_server::http_server(http_server::handler_type h) :
    handler(h),
    underlying_server(
        std::unique_ptr<text_server::extended_handler>(
            new internal_handler(handler)))

    //underlying_server(internal_handler(handler))
    // ^ custom trigger condition must be passed
    //   (and this trigger condition will have to refer to the handler)
{
    dprintf(logger::DEBUG, "http_server constructed");
}
*/

http_server::~http_server()
{
}

void http_server::listen(const char *address, int port)
{
    underlying_server.listen(address, port);
}

//
// request
//
void http_server::request::clear()
{
    method.clear();
    url.clear();
    version.clear();
    headers.clear();
    body.clear();
}

//
// response
//
http_server::response::response(writable &dst) :
    destination(dst),
    status(200),
    status_written(false),
    body_started(false),
    write_ended(false)
{
}

http_server::response::~response()
{
}

void http_server::response::add_header(const string &name, const string &value)
{
    headers.emplace_back(name, value);
}

void http_server::response::write_header(const string &name,
                                         const string &value)
{
    if (body_started) {
        throw write_error();
    }

    ensure_status();

    write_header(destination, name, value);
}

void http_server::response::write(const char *data, size_t length)
{
    if (!body_started) {
        write_headers();
        body_started = true;
    }

    destination.write(data, length);
}

void http_server::response::flush()
{
    if (!body_started) {
        write_headers();
        body_started = true;
    }
    destination.flush();
}

void http_server::response::end()
{
    if (!body_started) {
        write_headers();
        body_started = true;
    }
    destination.flush();
    destination.end();
    write_ended = true;
}

void http_server::response::write_status(writable &destination,
                                         unsigned status)
{
    string phrase;
    try {
        phrase = status_phrases.at(status);
    } catch (out_of_range) {
        phrase = undefined_status;
    }

    destination << "HTTP/1.1 " << status << ' ' << phrase << crlf;
}

void http_server::response::ensure_status()
{
    if (!status_written) {
        write_status(destination, status);
        status_written = true;
    }
}

void http_server::response::write_headers()
{
    if (body_started) {
        throw write_error();
    }

    ensure_status();

    for (auto I : headers) {
        write_header(destination, I.first, I.second);
    }
    destination << crlf;
}

//
// internal_handler
//
http_server::internal_handler::internal_handler(const handler_type &h) :
    handler(h),
    headers_completed(false),
    body_completed(false)
{
    id = ++last;
    dprintf(logger::DEBUG,
            "##\tinternal_handler %zu constructed; %p",
            id,
            this);
}

http_server::internal_handler::internal_handler(
    const http_server::internal_handler &that) :
        handler(that.handler),
        headers_completed(that.headers_completed),
        body_completed(that.body_completed),
        // ...
        id(++last)
{
    dprintf(logger::DEBUG,
            "##\tinternal_handler %zu copied from %zu; %p",
            this->id,
            that.id,
            this);
}

http_server::internal_handler::internal_handler(
    http_server::internal_handler &&that) :
        handler(std::move(that.handler)),
        headers_completed(that.headers_completed),
        body_completed(that.body_completed),
        // ...
        id(that.id)
{
    that.id = 0;
    dprintf(logger::DEBUG,
            "##\tinternal_handler %zu *moved*; %p",
            this->id,
            this);
}

//bool http_server::internal_handler::trigger(const char *data, size_t length)
bool http_server::internal_handler::operator()(const char *data, size_t length)
{
    //dprintf(logger::DEBUG, "trigger: %.*s", (int)length, data);
    //dprintf(logger::DEBUG, "internal_handler trigger: this=%p", this);
    if (length > 1 &&
        data[length - 2] == '\r' &&
        data[length - 1] == '\n')
    {
        return true;
    }

    if (headers_completed &&
        request.content_length &&
        request.content_length == request.body.length() + length)
    {
        dprintf(logger::DEBUG, "@! triggering handler for content_length");
        return true;
    }

    return false;
}

//void http_server::internal_handler::process(const char *data,
//                                            size_t length,
//                                            writable &destination)
void http_server::internal_handler::operator()(const char *data,
                                               size_t length,
                                               writable &destination)
{
    dprintf(logger::DEBUG, "internal_handler: this=%p", this);
    if (!headers_completed) {
        // still parsing headers
        if (length > 1 &&
            data[length - 2] == '\r' &&
            data[length - 1] == '\n')
        {
            length -= 2;
        } else {
            // trigger error
            dprintf(logger::INFO, "error: no crlf");
            cut_short(destination, 400);
            return;
        }

        if (request.method.empty()) {
            // not started yet
            parse_start_line(data, length);
            if (request.method.empty()) {
                // still not set, this is an error
                dprintf(logger::NOTICE, "could not parse method");
                cut_short(destination, 400);
                return;
            }
        } else {
            // header or blank expected
            if (!length) {
                dprintf(logger::DEBUG, "blank! l=%u", request.content_length);
                headers_completed = true;
                if (!request.content_length) {
                    // expect no content and respond right away
                    //dprintf(logger::DEBUG, "responding with 200");
                    //cut_short(destination, 200);
                    serve(destination);
                    // actually, call a handler // later
                }
                return;
            }

            raw_header h = parse_header(data, length);
            if (h.first.empty()) {
                //dprintf(logger::DEBUG,
                //        "error: could not parse header %.*s",
                //        length,
                //        data);
                cut_short(destination, 400);
                return;
            }
            //request.headers.push_back(h);
            auto it = request.headers.find(h.first);
            if (it != request.headers.end()) {
                it->second.append(1, ',');
                it->second.append(h.second);
            } else {
                request.headers.insert(h);
            }

            // fill dedicated fields for some headers
            if (h.first == "Content-Length") {
                dprintf(logger::DEBUG, "[%s]", h.second.c_str());
                request.content_length = stoul(h.second);
                dprintf(logger::DEBUG,
                        "contentlength %u",
                        request.content_length);
            }
        }
    } else {
        // TODO: cut off \r and \n?
        request.body.append(data, length);
        // and if line is empty, trigger the handler?

        // detecting body end in general case?
        // chunked request: not now
        // content length header: SHOULD be present, but not guaranteed
        // empty line? this is not correct
        // line-based text server will not work as a base of http server, alas
        // but now we can install a custom trigger

        if (request.content_length &&
            request.content_length == request.body.length())
        {
            dprintf(logger::DEBUG, "body ended?");
            //cut_short(destination, 200);
            serve(destination);
        }

        /*
        if (request.content_length) {
            // ...
        } else {

            if (length > 1 &&
                data[length - 2] == '\r' &&
                data[length - 1] == '\n')
            {
                fprintf(stderr, "body ended?\n");
                cut_short(destination, 200);
            }

        }
        */

    }

    //if (true) {
    //    response.destination = &destination;
    //    handler(request, response);
    //    if (connection: close header set) {
    //        response.end() // or destination.end
    //    }
    //}
}

void http_server::internal_handler::parse_start_line(const char *data,
                                                     size_t length)
{
    //A request-line begins with a method token, followed by a single space
    //(SP), the request-target, another single space (SP), the protocol
    //version, and ends with CRLF.
    //  request-line   = method SP request-target SP HTTP-version CRLF
    // so we need to split it, with minimal copying
    const char *p = data, *q;

    // method
    for (q = p; q < data + length && !isspace(*q); q++) ;
    if (q == p || q == data + length) {
        return; // method remains unset
    } else {
        request.method.assign(p, q - p);
    }

    // url
    for (p = q + 1; p < data + length && isspace(*p); p++) ;
    for (q = p; q < data + length && !isspace(*q); q++) ;
    if (q == p || q == data + length) {
        request.method.clear();
        return;
    } else {
        request.url.assign(p, q - p);
    }

    // version
    for (p = q + 1; p < data + length && isspace(*p); p++) ;
    for (q = p; q < data + length && !isspace(*q); q++) ;
    request.version.assign(p, q - p);
}

http_server::raw_header http_server::internal_handler::parse_header(
    const char *data,
    size_t length)
{
    const char *p, *q, *r;

    //p = static_cast<const char *>(memchr(data, length, ':'));
    //if (!p) {
    //    return raw_header();
    //}
    for (p = data; p < data + length && *p != ':'; p++) ;
    if (p == data + length) {
        return raw_header();
    }

    for (q = p + 1; q < data + length && isspace(*q); q++) ;
    for (r = data + length - 1; isspace(*r) && r >= q; r--) ;

    return raw_header(string(data, p - data), string(q, r - q + 1));
}

void http_server::internal_handler::clear()
{
    headers_completed = false;
    request.clear();
    //response.clear();
}

/*
void http_server::internal_handler::respond(writable &destination,
                                            const std::string &message,
                                            const std::string &)
{
    destination << message;
    //destination << "Content-Length: 0\r\n";
    destination << crlf;
    // ignore body for now

    destination.flush();
    // if (keep alive ) destination.close()
}
*/
void http_server::internal_handler::cut_short(writable &destination,
                                              unsigned status)
{
    response::write_status(destination, status);
    destination << crlf;
    destination.flush();
    // if (not keep alive) destination.end();
    destination.end(); // no keep alive for now
}

void http_server::internal_handler::serve(writable &destination)
{
    dprintf(logger::DEBUG, "serve");

    // construct the response
    class response response(destination);

    // and pass it to the handler
    handler(request, response);

    // some postprocessing: end if client did not, maybe set keepalive
    if (!response.write_ended) {
        response.flush();
        response.end();
    }
}

const string http_server::undefined_status = "Undefined";
const string http_server::crlf = "\r\n";

const map<unsigned, string> http_server::status_phrases =
{
    {   0, undefined_status },
    { 200, "OK" },
    { 400, "Bad Request" },
    { 404, "Not Found" },
    { 500, "Internal Server Error" }
    // ...
};

size_t http_server::internal_handler::last = 0;

} // namespace httptth
<commit_msg>double handler call fixed<commit_after>#include "http_server.hpp"
#include "exceptions.hpp"

#include <string.h>

using namespace std;

namespace httptth
{

//
// http_server
//
http_server::http_server(http_server::handler_type h) :
    handler(h),
    underlying_server(internal_handler(h))
{
    dprintf(logger::DEBUG, "http_server constructed");
}
/*
http_server::http_server(http_server::handler_type h) :
    handler(h),
    underlying_server(
        std::unique_ptr<text_server::extended_handler>(
            new internal_handler(handler)))

    //underlying_server(internal_handler(handler))
    // ^ custom trigger condition must be passed
    //   (and this trigger condition will have to refer to the handler)
{
    dprintf(logger::DEBUG, "http_server constructed");
}
*/

http_server::~http_server()
{
}

void http_server::listen(const char *address, int port)
{
    underlying_server.listen(address, port);
}

//
// request
//
void http_server::request::clear()
{
    method.clear();
    url.clear();
    version.clear();
    headers.clear();
    body.clear();
}

//
// response
//
http_server::response::response(writable &dst) :
    destination(dst),
    status(200),
    status_written(false),
    body_started(false),
    write_ended(false)
{
}

http_server::response::~response()
{
}

void http_server::response::add_header(const string &name, const string &value)
{
    headers.emplace_back(name, value);
}

void http_server::response::write_header(const string &name,
                                         const string &value)
{
    if (body_started) {
        throw write_error();
    }

    ensure_status();

    write_header(destination, name, value);
}

void http_server::response::write(const char *data, size_t length)
{
    if (!body_started) {
        write_headers();
        body_started = true;
    }

    destination.write(data, length);
}

void http_server::response::flush()
{
    if (!body_started) {
        write_headers();
        body_started = true;
    }
    destination.flush();
}

void http_server::response::end()
{
    if (!body_started) {
        write_headers();
        body_started = true;
    }
    destination.flush();
    destination.end();
    write_ended = true;
}

void http_server::response::write_status(writable &destination,
                                         unsigned status)
{
    string phrase;
    try {
        phrase = status_phrases.at(status);
    } catch (out_of_range) {
        phrase = undefined_status;
    }

    destination << "HTTP/1.1 " << status << ' ' << phrase << crlf;
}

void http_server::response::ensure_status()
{
    if (!status_written) {
        write_status(destination, status);
        status_written = true;
    }
}

void http_server::response::write_headers()
{
    if (body_started) {
        throw write_error();
    }

    ensure_status();

    for (auto I : headers) {
        write_header(destination, I.first, I.second);
    }
    destination << crlf;
}

//
// internal_handler
//
http_server::internal_handler::internal_handler(const handler_type &h) :
    handler(h),
    headers_completed(false),
    body_completed(false)
{
    id = ++last;
    dprintf(logger::DEBUG,
            "##\tinternal_handler %zu constructed; %p",
            id,
            this);
}

http_server::internal_handler::internal_handler(
    const http_server::internal_handler &that) :
        handler(that.handler),
        headers_completed(that.headers_completed),
        body_completed(that.body_completed),
        // ...
        id(++last)
{
    dprintf(logger::DEBUG,
            "##\tinternal_handler %zu copied from %zu; %p",
            this->id,
            that.id,
            this);
}

http_server::internal_handler::internal_handler(
    http_server::internal_handler &&that) :
        handler(std::move(that.handler)),
        headers_completed(that.headers_completed),
        body_completed(that.body_completed),
        // ...
        id(that.id)
{
    that.id = 0;
    dprintf(logger::DEBUG,
            "##\tinternal_handler %zu *moved*; %p",
            this->id,
            this);
}

//bool http_server::internal_handler::trigger(const char *data, size_t length)
bool http_server::internal_handler::operator()(const char *data, size_t length)
{
    //dprintf(logger::DEBUG, "trigger: %.*s", (int)length, data);
    //dprintf(logger::DEBUG, "internal_handler trigger: this=%p", this);
    if (length > 1 &&
        data[length - 2] == '\r' &&
        data[length - 1] == '\n')
    {
        return true;
    }

    if (headers_completed &&
        request.content_length &&
        request.content_length == request.body.length() + length)
    {
        dprintf(logger::DEBUG, "@! triggering handler for content_length");
        return true;
    }

    return false;
}

//void http_server::internal_handler::process(const char *data,
//                                            size_t length,
//                                            writable &destination)
void http_server::internal_handler::operator()(const char *data,
                                               size_t length,
                                               writable &destination)
{
    dprintf(logger::DEBUG, "internal_handler: this=%p", this);
    if (!headers_completed) {
        // still parsing headers
        if (length > 1 &&
            data[length - 2] == '\r' &&
            data[length - 1] == '\n')
        {
            length -= 2;
        } else {
            // trigger error
            dprintf(logger::INFO, "error: no crlf");
            cut_short(destination, 400);
            return;
        }

        if (request.method.empty()) {
            // not started yet
            parse_start_line(data, length);
            if (request.method.empty()) {
                // still not set, this is an error
                dprintf(logger::NOTICE, "could not parse method");
                cut_short(destination, 400);
                return;
            }
        } else {
            // header or blank expected
            if (!length) {
                dprintf(logger::DEBUG, "blank! l=%u", request.content_length);
                headers_completed = true;
                if (!request.content_length) {
                    // expect no content and respond right away
                    //dprintf(logger::DEBUG, "responding with 200");
                    //cut_short(destination, 200);
                    serve(destination);
                    // actually, call a handler // later
                }
                return;
            }

            raw_header h = parse_header(data, length);
            if (h.first.empty()) {
                //dprintf(logger::DEBUG,
                //        "error: could not parse header %.*s",
                //        length,
                //        data);
                cut_short(destination, 400);
                return;
            }
            //request.headers.push_back(h);
            auto it = request.headers.find(h.first);
            if (it != request.headers.end()) {
                it->second.append(1, ',');
                it->second.append(h.second);
            } else {
                request.headers.insert(h);
            }

            // fill dedicated fields for some headers
            if (h.first == "Content-Length") {
                dprintf(logger::DEBUG, "[%s]", h.second.c_str());
                request.content_length = stoul(h.second);
                dprintf(logger::DEBUG,
                        "contentlength %u",
                        request.content_length);
            }
        }
    } else {
        // TODO: cut off \r and \n?
        request.body.append(data, length);
        // and if line is empty, trigger the handler?

        // detecting body end in general case?
        // chunked request: not now
        // content length header: SHOULD be present, but not guaranteed
        // empty line? this is not correct
        // line-based text server will not work as a base of http server, alas
        // but now we can install a custom trigger

        if (!body_completed &&
            request.content_length &&
            request.content_length == request.body.length())
        {
            dprintf(logger::DEBUG, "body ended?");
            body_completed = true;
            //cut_short(destination, 200);
            serve(destination);
        }

        /*
        if (request.content_length) {
            // ...
        } else {

            if (length > 1 &&
                data[length - 2] == '\r' &&
                data[length - 1] == '\n')
            {
                fprintf(stderr, "body ended?\n");
                cut_short(destination, 200);
            }

        }
        */

    }

    //if (true) {
    //    response.destination = &destination;
    //    handler(request, response);
    //    if (connection: close header set) {
    //        response.end() // or destination.end
    //    }
    //}
}

void http_server::internal_handler::parse_start_line(const char *data,
                                                     size_t length)
{
    //A request-line begins with a method token, followed by a single space
    //(SP), the request-target, another single space (SP), the protocol
    //version, and ends with CRLF.
    //  request-line   = method SP request-target SP HTTP-version CRLF
    // so we need to split it, with minimal copying
    const char *p = data, *q;

    // method
    for (q = p; q < data + length && !isspace(*q); q++) ;
    if (q == p || q == data + length) {
        return; // method remains unset
    } else {
        request.method.assign(p, q - p);
    }

    // url
    for (p = q + 1; p < data + length && isspace(*p); p++) ;
    for (q = p; q < data + length && !isspace(*q); q++) ;
    if (q == p || q == data + length) {
        request.method.clear();
        return;
    } else {
        request.url.assign(p, q - p);
    }

    // version
    for (p = q + 1; p < data + length && isspace(*p); p++) ;
    for (q = p; q < data + length && !isspace(*q); q++) ;
    request.version.assign(p, q - p);
}

http_server::raw_header http_server::internal_handler::parse_header(
    const char *data,
    size_t length)
{
    const char *p, *q, *r;

    //p = static_cast<const char *>(memchr(data, length, ':'));
    //if (!p) {
    //    return raw_header();
    //}
    for (p = data; p < data + length && *p != ':'; p++) ;
    if (p == data + length) {
        return raw_header();
    }

    for (q = p + 1; q < data + length && isspace(*q); q++) ;
    for (r = data + length - 1; isspace(*r) && r >= q; r--) ;

    return raw_header(string(data, p - data), string(q, r - q + 1));
}

void http_server::internal_handler::clear()
{
    headers_completed = false;
    request.clear();
    //response.clear();
}

/*
void http_server::internal_handler::respond(writable &destination,
                                            const std::string &message,
                                            const std::string &)
{
    destination << message;
    //destination << "Content-Length: 0\r\n";
    destination << crlf;
    // ignore body for now

    destination.flush();
    // if (keep alive ) destination.close()
}
*/
void http_server::internal_handler::cut_short(writable &destination,
                                              unsigned status)
{
    response::write_status(destination, status);
    destination << crlf;
    destination.flush();
    // if (not keep alive) destination.end();
    destination.end(); // no keep alive for now
}

void http_server::internal_handler::serve(writable &destination)
{
    dprintf(logger::DEBUG, "serve");

    // construct the response
    class response response(destination);

    // and pass it to the handler
    handler(request, response);

    // some postprocessing: end if client did not, maybe set keepalive
    if (!response.write_ended) {
        response.flush();
        response.end();
    }
}

const string http_server::undefined_status = "Undefined";
const string http_server::crlf = "\r\n";

const map<unsigned, string> http_server::status_phrases =
{
    {   0, undefined_status },
    { 200, "OK" },
    { 400, "Bad Request" },
    { 404, "Not Found" },
    { 500, "Internal Server Error" }
    // ...
};

size_t http_server::internal_handler::last = 0;

} // namespace httptth
<|endoftext|>


<commit_before>#include <rclcpp/rclcpp.hpp>
#include <fake_ar_publisher_msgs/msg/ar_marker.hpp>
#include <visualization_msgs/msg/marker.hpp>

rclcpp::Publisher ar_pub;
rclcpp::Publisher visual_pub;

static std::string& camera_frame_name()
{
  static std::string camera_frame;
  return camera_frame;
}

// Singleton Instance of Object Position
static geometry_msgs::Pose& pose()
{
  static geometry_msgs::Pose pose;
  return pose;
}

// Given a marker w/ pose data, publish an RViz visualization
// You'll need to add a "Marker" visualizer in RVIZ AND define
// the "camera_frame" TF frame somewhere to see it.
static void pubVisualMarker(const fake_ar_publisher_msgs::ARMarker& m)
{
  const double width = 0.08;
  const double thickness = 0.005;

  visualization_msgs::Marker marker;
  marker.header.frame_id = m.header.frame_id;
  marker.header.stamp = rclcpp::Time::now();
  marker.ns = "ar_marker_visual";
  marker.id = 0;
  marker.type = visualization_msgs::Marker::CUBE;
  marker.action = visualization_msgs::Marker::ADD;
  marker.pose = m.pose.pose;
  marker.pose.position.z -= thickness / 2.0;
  marker.scale.x = width;
  marker.scale.y = width;
  marker.scale.z = thickness;
  marker.color.a = 1.0;
  marker.color.b = 1.0;

  visual_pub.publish(marker);
}

void pubCallback(const rclcpp::TimerEvent&)
{
  geometry_msgs::Pose p = pose();
  fake_ar_publisher::ARMarker m;
  m.header.frame_id = camera_frame_name();
  m.header.stamp = rclcpp::Time::now();
  m.pose.pose = p;

  ar_pub.publish(m);

  pubVisualMarker(m); // visualize the marker
}

int main(int argc, char **argv)
{
  // Set up ROS.
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("fake_ar_publisher")
  auto pnh = rclcpp::Node::make_shared("~");
  ar_pub = nh.advertise<fake_ar_publisher_msgs::ARMarker>("ar_pose_marker", 1);
  visual_pub = nh.advertise<visualization_msgs::Marker>("ar_pose_visual", 1);

  // init pose
  pose().orientation.w = 1.0; // facing straight up
  pnh.param<double>("x_pos", pose().position.x, -0.6);
  pnh.param<double>("y_pos", pose().position.y, 0.2);
  pnh.param<double>("z_pos", pose().position.z, 0.5);

  pnh.param<std::string>("camera_frame", camera_frame_name(), "camera_frame");

  RCLCPP_INFO("Starting simulated ARMarker publisher");
  rclcpp::Timer t = node.createTimer(rclcpp::Duration(0.1), pubCallback, false, true);
  rclcpp::spin();
}
<commit_msg>Make fake_ar_publisher into a class<commit_after>#include <rclcpp/rclcpp.hpp>
#include <fake_ar_publisher_msgs/msg/ar_marker.hpp>
#include <visualization_msgs/msg/marker.hpp>

using namespace std::chrono_literals;

static std::string& camera_frame_name()
{
  static std::string camera_frame;
  return camera_frame;
}

// Singleton Instance of Object Position
static geometry_msgs::msg::Pose& pose()
{
  static geometry_msgs::msg::Pose pose;
  return pose;
}

// Given a marker w/ pose data, publish an RViz visualization
// You'll need to add a "Marker" visualizer in RVIZ AND define
// the "camera_frame" TF frame somewhere to see it.

class FakeARPublisher : public rclcpp::Node
{
public:
  FakeARPublisher()
  : Node("fake_ar_publisher")
  {
    ar_pub_ = this->create_publisher<fake_ar_publisher_msgs::msg::ARMarker>("ar_pose_marker", 1);
    visual_pub_ = this->create_publisher<visualization_msgs::msg::Marker>("ar_pose_visual", 1);
    timer_ = this->create_wall_timer(100ms, std::bind(&FakeARPublisher::pubCallback, this));

  }

private:
  void pubVisualMarker(const fake_ar_publisher_msgs::msg::ARMarker& m)
  {
    const double width = 0.08;
    const double thickness = 0.005;

    visualization_msgs::msg::Marker marker;
    marker.header.frame_id = m.header.frame_id;
    marker.header.stamp = this->now();
    marker.ns = "ar_marker_visual";
    marker.id = 0;
    marker.type = visualization_msgs::msg::Marker::CUBE;
    marker.action = visualization_msgs::msg::Marker::ADD;
    marker.pose = m.pose.pose;
    marker.pose.position.z -= thickness / 2.0;
    marker.scale.x = width;
    marker.scale.y = width;
    marker.scale.z = thickness;
    marker.color.a = 1.0;
    marker.color.b = 1.0;

    visual_pub_->publish(marker);
  }

  void pubCallback()
  {
    geometry_msgs::msg::Pose p = pose();
    fake_ar_publisher_msgs::msg::ARMarker m;
    m.header.frame_id = camera_frame_name();
    m.header.stamp = this->now();
    m.pose.pose = p;

    ar_pub_->publish(m);

    pubVisualMarker(m); // visualize the marker
  }

  rclcpp::TimerBase::SharedPtr timer_;
  rclcpp::Publisher<fake_ar_publisher_msgs::msg::ARMarker>::SharedPtr ar_pub_;
  rclcpp::Publisher<visualization_msgs::msg::Marker>::SharedPtr visual_pub_;
};

int main(int argc, char **argv)
{
  // Set up ROS.
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("fake_ar_publisher");
  RCLCPP_INFO(node->get_logger(), "Starting simulated ARMarker publisher");
  rclcpp::spin(std::make_shared<FakeARPublisher>());
  rclcpp::shutdown();
  return 0;
}
<|endoftext|>


<commit_before>// Longest increasing subsequence (n log n implementation)
// -----------------------------------------
// Authors: Magnus Olsson  (magolsso@kth.se)
//          Calle Svensson (carlsven@kth.se)

#include <vector>

// Returns a vector of indices pointing to the elements in the longest increasing subsequence of list
std::vector<int> longest_seq(vector<int>& list)
{
  std::vector<int> indices;
  std::vector<int> p(list.size());

  if (list.empty()) return indices;

  indices.push_back(0);

  for (size_t i = 1; i < list.size(); i++) {
    //Is next element larger?
    if (list[indices.back()] < list[i]) {
      p[i] = indices.back();
      indices.push_back(i);
      continue;
    }

    //Binary search
    int low = 0;
    int hi = indices.size() - 1;
    while (low < hi) {
      int mid = (low + hi) / 2;
      if (list[indices[mid]] < list[i])
        low = mid + 1;
      else
        hi = mid;
    }

    if (list[i] < list[indices[low]]) {
      if (low > 0)
        p[i] = indices[low - 1];
      indices[low] = i;
    }
  }

  int j = indices.back();
  for (int i = indices.size() - 1; i >= 0; i--) {
    indices[i] = j;
    j = p[j];
  }

  return indices;
}<commit_msg>Reverted to fox comments<commit_after>// Longest increasing subsequence (n log n implementation)
// -----------------------------------------
// Authors: Magnus Olsson  (magolsso@kth.se)
//          Calle Svensson (carlsven@kth.se)

#include <vector>

// Returns a vector of indices pointing to the elements in the longest sequence
std::vector<int> longest_seq(vector<int>& list)
{
  std::vector<int> indices;
  std::vector<int> p(list.size());

  if (list.empty()) return indices;

  indices.push_back(0);

  // If next element list[i] is greater than last element of
  // current longest subsequence list[indices.back()], just push it at back of "indices" and continue
  for (size_t i = 1; i < list.size(); i++) {
    if (list[indices.back()] < list[i]) {
      p[i] = indices.back();
      indices.push_back(i);
      continue;
    }

    // Binary search to find the smallest element referenced by b which is just bigger than list[i]
    // Note : Binary search is performed on indices (and not list).
    // Size of indeces is always <=k and hence contributes O(log k) to complexity.
    int low = 0;
    int hi = indices.size()-1;
    while (low < hi) {
      int mid = (low + hi) / 2;
      if (list[indices[mid]] < list[i])
        low = mid + 1;
      else
        hi = mid;
    }

    // Update indeces if new value is smaller than previously referenced value
    if (list[i] < list[indices[low]]) {
      if (low > 0)
        p[i] = indices[low-1];
      indices[low] = i;
    }
  }

  int j = indices.back();
  for (int i = indices.size()-1; i >= 0; i--) {
    indices[i] = j;
    j = p[j];
  }

  return indices;
}<|endoftext|>


<commit_before>#include <signal.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

static void signal_reload(int);
static void signal_stop(int);

EventSystem::EventSystem(void)
: log_("/event/system"),
  queue_(),
  reload_(),
  stop_(),
  interest_queue_(),
  timeout_queue_(),
  poll_()
{
	INFO(log_) << "Starting event system.";

	signal(SIGHUP, signal_reload);
	signal(SIGINT, signal_stop);
}

EventSystem::~EventSystem()
{
}

Action *
EventSystem::poll(const EventPoll::Type& type, int fd, EventCallback *cb)
{
	Action *a = poll_.poll(type, fd, cb);
	return (a);
}

Action *
EventSystem::register_interest(const EventInterest& interest, Callback *cb)
{
	Action *a = interest_queue_[interest].append(cb);
	return (a);
}

Action *
EventSystem::schedule(Callback *cb)
{
	Action *a = queue_.append(cb);
	return (a);
}

Action *
EventSystem::timeout(unsigned secs, Callback *cb)
{
	Action *a = timeout_queue_.append(secs, cb);
	return (a);
}

void
EventSystem::start(void)
{
	for (;;) {
		/*
		 * If we have been told to stop, fire all shutdown events.
		 */
		if (stop_ && !interest_queue_[EventInterestStop].empty()) {
			INFO(log_) << "Running stop handlers.";
			if (interest_queue_[EventInterestStop].drain())
				ERROR(log_) << "Stop handlers added other stop handlers.";
			INFO(log_) << "Stop handlers have been run.";
		}

		/*
		 * If we have been told to reload, fire all shutdown events.
		 */
		if (reload_ && !interest_queue_[EventInterestReload].empty()) {
			INFO(log_) << "Running reload handlers.";
			interest_queue_[EventInterestReload].drain();
			INFO(log_) << "Reload handlers have been run.";

			reload_ = false;
			signal(SIGHUP, signal_reload);
		}

		/*
		 * If there are time-triggered events whose time has come,
		 * run them.
		 */
		if (!timeout_queue_.empty()) {
			while (timeout_queue_.ready())
				timeout_queue_.perform();
		}

		/*
		 * And then run a pending callback.
		 */
		while (!queue_.empty() && !timeout_queue_.ready()) {
			queue_.perform();
			if (stop_ || reload_)
				break;
		}

		/*
		 * Do a quick poll if necessary.
		 */
		if (!queue_.empty() || timeout_queue_.ready()) {
			if (!poll_.idle())
				poll_.poll();
			continue;
		}

		/*
		 * But if there are no pending callbacks, and no timers or
		 * file descriptors being polled, stop.
		 */
		if (timeout_queue_.empty() && poll_.idle())
			break;
		/*
		 * If there are timers ticking down, then let the poll module
		 * block until a timer will be ready.
		 * XXX Maybe block 1 second less, just in case?  We'll never
		 * be a realtime system though, so any attempt at pretending
		 * to be one, beyond giving time events priority at the top of
		 * this loop, is probably a mistake.
		 */
		if (!timeout_queue_.empty()) {
			poll_.wait(timeout_queue_.interval());
			continue;
		}
		/*
		 * If, however, there's nothing sensitive to time, but someone
		 * has a file descriptor that can be blocked on, just block on it
		 * indefinitely.
		 */
		poll_.wait();
	}
}

void
EventSystem::stop(void)
{
	signal(SIGINT, SIG_DFL);
	INFO(log_) << "Stopping event system.";
	stop_ = true;
}

void
EventSystem::reload(void)
{
	signal(SIGHUP, SIG_IGN);
	INFO(log_) << "Running reload events.";
	reload_ = true;
}

static void
signal_reload(int)
{
	EventSystem::instance()->reload();
}

static void
signal_stop(int)
{
	EventSystem::instance()->stop();
}
<commit_msg>Simplify code and do poll regularly even in the infinite callbacks case.<commit_after>#include <signal.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

static void signal_reload(int);
static void signal_stop(int);

EventSystem::EventSystem(void)
: log_("/event/system"),
  queue_(),
  reload_(),
  stop_(),
  interest_queue_(),
  timeout_queue_(),
  poll_()
{
	INFO(log_) << "Starting event system.";

	signal(SIGHUP, signal_reload);
	signal(SIGINT, signal_stop);
}

EventSystem::~EventSystem()
{
}

Action *
EventSystem::poll(const EventPoll::Type& type, int fd, EventCallback *cb)
{
	Action *a = poll_.poll(type, fd, cb);
	return (a);
}

Action *
EventSystem::register_interest(const EventInterest& interest, Callback *cb)
{
	Action *a = interest_queue_[interest].append(cb);
	return (a);
}

Action *
EventSystem::schedule(Callback *cb)
{
	Action *a = queue_.append(cb);
	return (a);
}

Action *
EventSystem::timeout(unsigned secs, Callback *cb)
{
	Action *a = timeout_queue_.append(secs, cb);
	return (a);
}

void
EventSystem::start(void)
{
	for (;;) {
		/*
		 * If we have been told to stop, fire all shutdown events.
		 */
		if (stop_ && !interest_queue_[EventInterestStop].empty()) {
			INFO(log_) << "Running stop handlers.";
			if (interest_queue_[EventInterestStop].drain())
				ERROR(log_) << "Stop handlers added other stop handlers.";
			INFO(log_) << "Stop handlers have been run.";
		}

		/*
		 * If we have been told to reload, fire all shutdown events.
		 */
		if (reload_ && !interest_queue_[EventInterestReload].empty()) {
			INFO(log_) << "Running reload handlers.";
			interest_queue_[EventInterestReload].drain();
			INFO(log_) << "Reload handlers have been run.";

			reload_ = false;
			signal(SIGHUP, signal_reload);
		}

		/*
		 * If there are time-triggered events whose time has come,
		 * run them.
		 */
		if (!timeout_queue_.empty()) {
			while (timeout_queue_.ready())
				timeout_queue_.perform();
		}

		/*
		 * And then run a pending callback.
		 */
		while (!queue_.empty() && !timeout_queue_.ready()) {
			queue_.perform();
			if (stop_ || reload_)
				break;
			if (!poll_.idle())
				poll_.poll();
		}

		/*
		 * Do a quick poll if necessary.
		 */
		if (!queue_.empty() || timeout_queue_.ready())
			continue;

		/*
		 * But if there are no pending callbacks, and no timers or
		 * file descriptors being polled, stop.
		 */
		if (timeout_queue_.empty() && poll_.idle())
			break;
		/*
		 * If there are timers ticking down, then let the poll module
		 * block until a timer will be ready.
		 * XXX Maybe block 1 second less, just in case?  We'll never
		 * be a realtime system though, so any attempt at pretending
		 * to be one, beyond giving time events priority at the top of
		 * this loop, is probably a mistake.
		 */
		if (!timeout_queue_.empty()) {
			poll_.wait(timeout_queue_.interval());
			continue;
		}
		/*
		 * If, however, there's nothing sensitive to time, but someone
		 * has a file descriptor that can be blocked on, just block on it
		 * indefinitely.
		 */
		poll_.wait();
	}
}

void
EventSystem::stop(void)
{
	signal(SIGINT, SIG_DFL);
	INFO(log_) << "Stopping event system.";
	stop_ = true;
}

void
EventSystem::reload(void)
{
	signal(SIGHUP, SIG_IGN);
	INFO(log_) << "Running reload events.";
	reload_ = true;
}

static void
signal_reload(int)
{
	EventSystem::instance()->reload();
}

static void
signal_stop(int)
{
	EventSystem::instance()->stop();
}
<|endoftext|>


<commit_before>// Copyright 2014 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 "content/browser/service_worker/service_worker_cache_listener.h"

#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/service_worker/service_worker_cache_storage_manager.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"

namespace content {

using blink::WebServiceWorkerCacheError;

namespace {

WebServiceWorkerCacheError ToWebServiceWorkerCacheError(
    ServiceWorkerCacheStorage::CacheStorageError err) {
  switch (err) {
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR:
      NOTREACHED();
      return WebServiceWorkerCacheError::
          WebServiceWorkerCacheErrorNotImplemented;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_IMPLEMENTED:
      return WebServiceWorkerCacheError::
          WebServiceWorkerCacheErrorNotImplemented;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND:
      return WebServiceWorkerCacheError::WebServiceWorkerCacheErrorNotFound;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_EXISTS:
      return WebServiceWorkerCacheError::WebServiceWorkerCacheErrorExists;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_STORAGE:
      // TODO(jkarlin): Changethis to CACHE_STORAGE_ERROR_STORAGE once that's
      // added.
      return WebServiceWorkerCacheError::WebServiceWorkerCacheErrorNotFound;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_EMPTY_KEY:
      // TODO(jkarlin): Update this to CACHE_STORAGE_ERROR_EMPTY_KEY once that's
      // added.
      return WebServiceWorkerCacheError::WebServiceWorkerCacheErrorNotFound;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_CLOSING:
      // TODO(jkarlin): Update this to CACHE_STORAGE_ERROR_CLOSING once that's
      // added.
      return WebServiceWorkerCacheError::WebServiceWorkerCacheErrorNotFound;
  }
  NOTREACHED();
  return WebServiceWorkerCacheError::WebServiceWorkerCacheErrorNotImplemented;
}

}  // namespace

ServiceWorkerCacheListener::ServiceWorkerCacheListener(
    ServiceWorkerVersion* version,
    base::WeakPtr<ServiceWorkerContextCore> context)
    : version_(version), context_(context), weak_factory_(this) {
}

ServiceWorkerCacheListener::~ServiceWorkerCacheListener() {
}

bool ServiceWorkerCacheListener::OnMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(ServiceWorkerCacheListener, message)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageGet,
                        OnCacheStorageGet)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageHas,
                        OnCacheStorageHas)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageCreate,
                        OnCacheStorageCreate)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageDelete,
                        OnCacheStorageDelete)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageKeys,
                        OnCacheStorageKeys)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

void ServiceWorkerCacheListener::OnCacheStorageGet(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->GetCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageGetCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageHas(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->HasCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageHasCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageCreate(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->CreateCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageCreateCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageDelete(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->DeleteCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageDeleteCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageKeys(int request_id) {
  context_->cache_manager()->EnumerateCaches(
      version_->scope().GetOrigin(),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageKeysCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::Send(const IPC::Message& message) {
  version_->embedded_worker()->SendMessage(message);
}

void ServiceWorkerCacheListener::OnCacheStorageGetCallback(
    int request_id,
    int cache_id,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageGetError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageGetSuccess(request_id, cache_id));
}

void ServiceWorkerCacheListener::OnCacheStorageHasCallback(
    int request_id,
    bool has_cache,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageHasError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  if (!has_cache) {
    Send(ServiceWorkerMsg_CacheStorageHasError(
        request_id,
        WebServiceWorkerCacheError::WebServiceWorkerCacheErrorNotFound));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageHasSuccess(request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageCreateCallback(
    int request_id,
    int cache_id,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageCreateError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageCreateSuccess(request_id, cache_id));
}

void ServiceWorkerCacheListener::OnCacheStorageDeleteCallback(
    int request_id,
    bool deleted,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (!deleted ||
      error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageDeleteError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageDeleteSuccess(request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageKeysCallback(
    int request_id,
    const std::vector<std::string>& strings,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageKeysError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }

  std::vector<base::string16> string16s;
  for (size_t i = 0, max = strings.size(); i < max; ++i) {
    string16s.push_back(base::UTF8ToUTF16(strings[i]));
  }
  Send(ServiceWorkerMsg_CacheStorageKeysSuccess(request_id, string16s));
}

}  // namespace content
<commit_msg>use c++03 style enum scope<commit_after>// Copyright 2014 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 "content/browser/service_worker/service_worker_cache_listener.h"

#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/service_worker/service_worker_cache_storage_manager.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"

namespace content {

using blink::WebServiceWorkerCacheError;

namespace {

WebServiceWorkerCacheError ToWebServiceWorkerCacheError(
    ServiceWorkerCacheStorage::CacheStorageError err) {
  switch (err) {
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR:
      NOTREACHED();
      return blink::WebServiceWorkerCacheErrorNotImplemented;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_IMPLEMENTED:
      return blink::WebServiceWorkerCacheErrorNotImplemented;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND:
      return blink::WebServiceWorkerCacheErrorNotFound;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_EXISTS:
      return blink::WebServiceWorkerCacheErrorExists;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_STORAGE:
      // TODO(jkarlin): Changethis to CACHE_STORAGE_ERROR_STORAGE once that's
      // added.
      return blink::WebServiceWorkerCacheErrorNotFound;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_EMPTY_KEY:
      // TODO(jkarlin): Update this to CACHE_STORAGE_ERROR_EMPTY_KEY once that's
      // added.
      return blink::WebServiceWorkerCacheErrorNotFound;
    case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_CLOSING:
      // TODO(jkarlin): Update this to CACHE_STORAGE_ERROR_CLOSING once that's
      // added.
      return blink::WebServiceWorkerCacheErrorNotFound;
  }
  NOTREACHED();
  return blink::WebServiceWorkerCacheErrorNotImplemented;
}

}  // namespace

ServiceWorkerCacheListener::ServiceWorkerCacheListener(
    ServiceWorkerVersion* version,
    base::WeakPtr<ServiceWorkerContextCore> context)
    : version_(version), context_(context), weak_factory_(this) {
}

ServiceWorkerCacheListener::~ServiceWorkerCacheListener() {
}

bool ServiceWorkerCacheListener::OnMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(ServiceWorkerCacheListener, message)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageGet,
                        OnCacheStorageGet)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageHas,
                        OnCacheStorageHas)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageCreate,
                        OnCacheStorageCreate)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageDelete,
                        OnCacheStorageDelete)
    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageKeys,
                        OnCacheStorageKeys)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

void ServiceWorkerCacheListener::OnCacheStorageGet(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->GetCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageGetCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageHas(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->HasCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageHasCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageCreate(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->CreateCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageCreateCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageDelete(
    int request_id,
    const base::string16& cache_name) {
  context_->cache_manager()->DeleteCache(
      version_->scope().GetOrigin(),
      base::UTF16ToUTF8(cache_name),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageDeleteCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageKeys(int request_id) {
  context_->cache_manager()->EnumerateCaches(
      version_->scope().GetOrigin(),
      base::Bind(&ServiceWorkerCacheListener::OnCacheStorageKeysCallback,
                 weak_factory_.GetWeakPtr(),
                 request_id));
}

void ServiceWorkerCacheListener::Send(const IPC::Message& message) {
  version_->embedded_worker()->SendMessage(message);
}

void ServiceWorkerCacheListener::OnCacheStorageGetCallback(
    int request_id,
    int cache_id,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageGetError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageGetSuccess(request_id, cache_id));
}

void ServiceWorkerCacheListener::OnCacheStorageHasCallback(
    int request_id,
    bool has_cache,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageHasError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  if (!has_cache) {
    Send(ServiceWorkerMsg_CacheStorageHasError(
        request_id,
        blink::WebServiceWorkerCacheErrorNotFound));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageHasSuccess(request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageCreateCallback(
    int request_id,
    int cache_id,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageCreateError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageCreateSuccess(request_id, cache_id));
}

void ServiceWorkerCacheListener::OnCacheStorageDeleteCallback(
    int request_id,
    bool deleted,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (!deleted ||
      error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageDeleteError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }
  Send(ServiceWorkerMsg_CacheStorageDeleteSuccess(request_id));
}

void ServiceWorkerCacheListener::OnCacheStorageKeysCallback(
    int request_id,
    const std::vector<std::string>& strings,
    ServiceWorkerCacheStorage::CacheStorageError error) {
  if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
    Send(ServiceWorkerMsg_CacheStorageKeysError(
        request_id, ToWebServiceWorkerCacheError(error)));
    return;
  }

  std::vector<base::string16> string16s;
  for (size_t i = 0, max = strings.size(); i < max; ++i) {
    string16s.push_back(base::UTF8ToUTF16(strings[i]));
  }
  Send(ServiceWorkerMsg_CacheStorageKeysSuccess(request_id, string16s));
}

}  // namespace content
<|endoftext|>


<commit_before>/************************************************************************
  This file is part of Freekick.

  Freekick is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Freekick is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with Freekick.  If not, see <http://www.gnu.org/licenses/>.

  Copyright Antti Salonen, 2008
**************************************************************************/

#include "ServerManager.h"

namespace freekick
{
    namespace match
    {
        namespace server
        {
            ServerManager::ServerManager(unsigned int port,
                                         boost::shared_ptr<freekick::match::MatchStatus> ms,
                                         const std::string& servername,
                                         const std::string& greeting)
                : mPort(port),
                  clients(new ClientList()),
                  mMatchStatus(ms),
                  im(new InputMonitor(ms)),
                  p(new Physics(ms, im)),
                  r(new Rules(ms, p)),
                  d(new Dispatcher(clients, this, p, r, ms)),
                  cel(new ClientEventListener(clients, im, d)),
                  console(new Console(ms)),
                  name(servername),
                  greet(greeting),
                  protocol_version("0.2")
            {
            }

            ServerManager::~ServerManager()
            {
                clients->clear();
                std::cerr << "Stopping listening.\n";
                stopListening();
            }

            bool ServerManager::run()
            {
                boost::thread console_thread(boost::bind(&freekick::match::server::Console::run, console));
                std::cerr << "Starting physics\n";
                boost::thread physics_thread(boost::bind(&freekick::match::server::Physics::run, p));
                std::cerr << "Starting listening on port " << mPort << std::endl;
                boost::thread listen_thread(boost::bind(&freekick::match::server::ServerManager::startListening, this, mPort));
                console_thread.join();
                // listen_thread.interrupt();
                return true;
            }

            void ServerManager::client_connected(client_id id)
            {
                std::cerr << "Client " << id << " connected.\n";
                messages::ServerInitMessage sim(name, protocol_version, greet);
                try
                {
                    write(sim.toString(), id);
                }
                catch(...)
                {
                    std::cerr << "Error while writing to client " << id << "; disconnecting.\n";
                    disconnect(id);
                }
            }

            void ServerManager::client_disconnected(client_id id)
            {
                ClientList::iterator it;
                it = clients->find(id);
                if (it != clients->end())
                {
                    clients->erase(it);
                }
                remove_from_group(id, 1);
                std::cerr << "Client " << id << " disconnected.\n";
            }

            void ServerManager::client_input(client_id id, std::string& msg)
            {
                ClientList::iterator it;
                it = clients->find(id);
                if (it != clients->end())
                {
                    cel->newData(id, msg);
                    return;
                }
                else    // handshake
                {
                    try
                    {
                        messages::ClientInitMessage cim(msg);
                        std::string this_type;
                        cim.getType(this_type);
                        ClientType this_controller;
                        if(this_type == "A")
                            this_controller = AIClient;
                        else if (this_type == "H")
                            this_controller = HumanClient;
                        else
                        {
                            std::string err_msg = "Invalid controller type: ";
                            err_msg += this_type;
                            throw err_msg.c_str();
                        }

                        std::pair<ClientList::iterator, bool> ins =
                            clients->insert(std::pair<int, boost::shared_ptr<Client> >
                                            (id, boost::shared_ptr<Client>(new Client(id, (this_controller == AIClient)))));

                        add_to_group(id, 1);    // TODO: enum instead of 1 (gid)
                    }
                    catch (const char* s)
                    {
                        std::cerr << "Could not parse ClientInitMessage: " << s << std::endl;
                        disconnect(id);
                        return;
                    }
                    catch (...)
                    {
                        std::cerr << "Could not parse ClientInitMessage" << std::endl;
                        disconnect(id);
                        return;
                    }
                }
            }
        }
    }
}
<commit_msg>server: added creation of match result file after finishing match<commit_after>/************************************************************************
  This file is part of Freekick.

  Freekick is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Freekick is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with Freekick.  If not, see <http://www.gnu.org/licenses/>.

  Copyright Antti Salonen, 2008
**************************************************************************/

#include "ServerManager.h"

namespace freekick
{
    namespace match
    {
        namespace server
        {
            ServerManager::ServerManager(unsigned int port,
                                         boost::shared_ptr<freekick::match::MatchStatus> ms,
                                         const std::string& servername,
                                         const std::string& greeting)
                : mPort(port),
                  clients(new ClientList()),
                  mMatchStatus(ms),
                  im(new InputMonitor(ms)),
                  p(new Physics(ms, im)),
                  r(new Rules(ms, p)),
                  d(new Dispatcher(clients, this, p, r, ms)),
                  cel(new ClientEventListener(clients, im, d)),
                  console(new Console(ms)),
                  name(servername),
                  greet(greeting),
                  protocol_version("0.2")
            {
            }

            ServerManager::~ServerManager()
            {
                clients->clear();
                std::cerr << "Stopping listening.\n";
                stopListening();
            }

            bool ServerManager::run()
            {
                boost::thread console_thread(boost::bind(&freekick::match::server::Console::run, console));
                std::cerr << "Starting physics\n";
                boost::thread physics_thread(boost::bind(&freekick::match::server::Physics::run, p));
                std::cerr << "Starting listening on port " << mPort << std::endl;
                boost::thread listen_thread(boost::bind(&freekick::match::server::ServerManager::startListening, this, mPort));
                physics_thread.join();
                // console_thread.join();
                // listen_thread.interrupt();
                stopListening();
                mMatchStatus->createMatchResultFile();
                return true;
            }

            void ServerManager::client_connected(client_id id)
            {
                std::cerr << "Client " << id << " connected.\n";
                messages::ServerInitMessage sim(name, protocol_version, greet);
                try
                {
                    write(sim.toString(), id);
                }
                catch(...)
                {
                    std::cerr << "Error while writing to client " << id << "; disconnecting.\n";
                    disconnect(id);
                }
            }

            void ServerManager::client_disconnected(client_id id)
            {
                ClientList::iterator it;
                it = clients->find(id);
                if (it != clients->end())
                {
                    clients->erase(it);
                }
                remove_from_group(id, 1);
                std::cerr << "Client " << id << " disconnected.\n";
            }

            void ServerManager::client_input(client_id id, std::string& msg)
            {
                ClientList::iterator it;
                it = clients->find(id);
                if (it != clients->end())
                {
                    cel->newData(id, msg);
                    return;
                }
                else    // handshake
                {
                    try
                    {
                        messages::ClientInitMessage cim(msg);
                        std::string this_type;
                        cim.getType(this_type);
                        ClientType this_controller;
                        if(this_type == "A")
                            this_controller = AIClient;
                        else if (this_type == "H")
                            this_controller = HumanClient;
                        else
                        {
                            std::string err_msg = "Invalid controller type: ";
                            err_msg += this_type;
                            throw err_msg.c_str();
                        }

                        std::pair<ClientList::iterator, bool> ins =
                            clients->insert(std::pair<int, boost::shared_ptr<Client> >
                                            (id, boost::shared_ptr<Client>(new Client(id, (this_controller == AIClient)))));

                        add_to_group(id, 1);    // TODO: enum instead of 1 (gid)
                    }
                    catch (const char* s)
                    {
                        std::cerr << "Could not parse ClientInitMessage: " << s << std::endl;
                        disconnect(id);
                        return;
                    }
                    catch (...)
                    {
                        std::cerr << "Could not parse ClientInitMessage" << std::endl;
                        disconnect(id);
                        return;
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2003 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cxxtools/iconvstream.h"
#include "cxxtools/log.h"
#include <string.h>
#include "config.h"
#include <errno.h>
#include <stdexcept>
#include <sstream>

log_define("cxxtools.iconvstream")

namespace cxxtools
{

iconv_error::iconv_error(size_t pos)
  : std::runtime_error(std::string()), pos(pos)
{
}

size_t iconv_error::position() const throw()
{
  return pos;
}

const char *iconv_error::what() const throw()
{
  if (msg.empty())
  {
    std::ostringstream ss;

    ss << "iconv failed to convert character at position: " << pos;
    msg = ss.str();
  }

  return msg.c_str();
}

iconv_error::~iconv_error() throw()
{
}

iconvstreambuf* iconvstreambuf::open(std::ostream& sink_,
  const char* tocode, const char* fromcode)
{
  open(sink_, tocode, fromcode, iconvstreambuf::mode_default);
}

iconvstreambuf* iconvstreambuf::open(std::ostream& sink_,
  const char* tocode, const char* fromcode, mode_t mode_)
{
  log_debug("iconv_open(\"" << tocode << "\", \"" << fromcode <<
          "\", " << mode_ << ")");
  mode = mode_;
  sink = &sink_;
  pos = 0;

  if (!conv.open(tocode, fromcode))
  {
    if (errno == EINVAL)
    {
      std::string msg = "conversion not supported; from=\"";
      msg += fromcode;
      msg += "\" to \"";
      msg += tocode;
      log_warn(msg);
      throw std::runtime_error(msg);
    }
    return 0;
  }

  log_debug("iconv-opened");

  return this;
}

iconvstreambuf* iconvstreambuf::close() throw()
{
  if (conv.is_open())
  {
    sync();
    log_debug("iconv.close(...)");
    if (conv.close())
    {
      return this;
    }
    else
      return 0;
  }
  else
    return this;
}

iconvstreambuf::int_type iconvstreambuf::overflow(int_type c)
{
  log_debug("overflow(" << c << ')');

  if (sink == 0)
  {
    log_error("no sink");
    return traits_type::eof();
  }
  else if (pptr() == 0 || pptr() == buffer)
  {
    log_debug("empty put-area");
    if (c != traits_type::eof())
    {
      if (pptr() == 0)
      {
        log_debug("initialize buffer");
        setp(buffer, buffer + (sizeof(buffer) - 1));
      }
      *pptr() = (char_type)c;
      pbump(1);
    }
    return 0;
  }
  else
  {
    char outbuf[sizeof(buffer)*2];;

    size_t inbytesleft = pptr() - buffer;
    if (c != traits_type::eof())
    {
      *pptr() = (char_type)c;
      ++inbytesleft;
    }
    size_t outbytesleft = sizeof(outbuf);

    ICONV_CONST char* inbufptr = buffer;
    char* outbufptr = outbuf;

    // convert as many charachters as possible
    log_debug("iconv(...) " << inbytesleft << " bytes");
    bool iconv_ret = conv.convert(&inbufptr, &inbytesleft,
          &outbufptr, &outbytesleft);

    pos += inbufptr - buffer;
    iconv_ret = iconv_ret || errno == EINVAL || errno == E2BIG;

    log_debug("pass " << outbufptr - outbuf << " bytes to sink");
    sink->write(outbuf, outbufptr - outbuf);

    if (sink->fail())
    {
      log_warn("sink failed");
      return traits_type::eof();
    }

    log_debug("reinitialize put area");
    setp(buffer, buffer + (sizeof(buffer) - 1));

    if (!iconv_ret) {
      switch (mode) {
        case iconvstreambuf::mode_skip:
          log_warn("convert failed, skipping byte");
          --inbytesleft;
          ++inbufptr;
          iconv_ret = true;
        break;
        case iconvstreambuf::mode_throw:
          log_warn("convert failed, throwing exception");
          throw iconv_error(pos);
        default:
          return traits_type::eof();
      }
    }

    // move left bytes to the start of buffer and reinitialize buffer
    if (inbytesleft > 0)
    {
      log_debug("move " << inbytesleft << " bytes to the start");
      sputn(inbufptr, inbytesleft);
    }

    return 0;
  }
}

iconvstream::int_type iconvstreambuf::underflow()
{
  log_warn("underflow not supported in iconvstreambuf");
  return traits_type::eof();
}

int iconvstreambuf::sync()
{
  log_debug("sync");

  if (pptr() == 0 || pptr() == buffer)
    return 0;
  else if (sink)
  {
    size_t ob, ob2;
    int_type ret;
    do
    {
      ob = pptr() - buffer;
      ret = overflow(traits_type::eof());
      ob2 = pptr() - buffer;
    } while (ob2 > 0 && ob2 < ob);

    log_debug("flush sink");
    sink->flush();

    return ret == traits_type::eof() || sink->fail() ? -1 : 0;
  }
  else
  {
    log_warn("no sink");
    return 0;
  }
}

std::streampos iconvstreambuf::seekoff(std::streamoff off,
  std::ios_base::seekdir way, std::ios_base::openmode which)
{
  // modify off to by relative position from current position
  switch (way) {
    case std::ios_base::beg:
      off -= pos;
    case std::ios_base::cur:
      break;
    default:
      return std::streampos(-1);
  }

  if (which == std::ios_base::in) {
    char *buf_p = gptr() + off;
    // alow seek only on valid data
    if (buf_p < eback() || buf_p > pptr())
        return std::streampos(-1);

    gbump(off);
    pos += off;
    return pos;
  }

  if (which == std::ios_base::out) {
    char *buf_p = pptr() + off;
    // alow seek only on valid data
    if (buf_p < pbase() || buf_p > pptr())
        return std::streampos(-1);

    pbump(off);
    return pos + off;
  }

  return std::streampos(-1);
}

std::streampos iconvstreambuf::seekpos(std::streampos sp,
  std::ios_base::openmode which)
{
  return seekoff(sp, std::ios_base::beg, which);
}

void iconvstream::open(std::ostream& sink_,
  const char* tocode, const char* fromcode)
{
  open(sink_, tocode, fromcode, iconvstreambuf::mode_default);
}

void iconvstream::open(std::ostream& sink_,
  const char* tocode, const char* fromcode,
  iconvstreambuf::mode_t mode)
{
  if (!fail() && streambuf.open(sink_, tocode, fromcode, mode) == 0)
    setstate(std::ios::failbit);
}

}
<commit_msg>add missing return statement<commit_after>/*
 * Copyright (C) 2003 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cxxtools/iconvstream.h"
#include "cxxtools/log.h"
#include <string.h>
#include "config.h"
#include <errno.h>
#include <stdexcept>
#include <sstream>

log_define("cxxtools.iconvstream")

namespace cxxtools
{

iconv_error::iconv_error(size_t pos)
  : std::runtime_error(std::string()), pos(pos)
{
}

size_t iconv_error::position() const throw()
{
  return pos;
}

const char *iconv_error::what() const throw()
{
  if (msg.empty())
  {
    std::ostringstream ss;

    ss << "iconv failed to convert character at position: " << pos;
    msg = ss.str();
  }

  return msg.c_str();
}

iconv_error::~iconv_error() throw()
{
}

iconvstreambuf* iconvstreambuf::open(std::ostream& sink_,
  const char* tocode, const char* fromcode)
{
  open(sink_, tocode, fromcode, iconvstreambuf::mode_default);
  return this;
}

iconvstreambuf* iconvstreambuf::open(std::ostream& sink_,
  const char* tocode, const char* fromcode, mode_t mode_)
{
  log_debug("iconv_open(\"" << tocode << "\", \"" << fromcode <<
          "\", " << mode_ << ")");
  mode = mode_;
  sink = &sink_;
  pos = 0;

  if (!conv.open(tocode, fromcode))
  {
    if (errno == EINVAL)
    {
      std::string msg = "conversion not supported; from=\"";
      msg += fromcode;
      msg += "\" to \"";
      msg += tocode;
      log_warn(msg);
      throw std::runtime_error(msg);
    }
    return 0;
  }

  log_debug("iconv-opened");

  return this;
}

iconvstreambuf* iconvstreambuf::close() throw()
{
  if (conv.is_open())
  {
    sync();
    log_debug("iconv.close(...)");
    if (conv.close())
    {
      return this;
    }
    else
      return 0;
  }
  else
    return this;
}

iconvstreambuf::int_type iconvstreambuf::overflow(int_type c)
{
  log_debug("overflow(" << c << ')');

  if (sink == 0)
  {
    log_error("no sink");
    return traits_type::eof();
  }
  else if (pptr() == 0 || pptr() == buffer)
  {
    log_debug("empty put-area");
    if (c != traits_type::eof())
    {
      if (pptr() == 0)
      {
        log_debug("initialize buffer");
        setp(buffer, buffer + (sizeof(buffer) - 1));
      }
      *pptr() = (char_type)c;
      pbump(1);
    }
    return 0;
  }
  else
  {
    char outbuf[sizeof(buffer)*2];;

    size_t inbytesleft = pptr() - buffer;
    if (c != traits_type::eof())
    {
      *pptr() = (char_type)c;
      ++inbytesleft;
    }
    size_t outbytesleft = sizeof(outbuf);

    ICONV_CONST char* inbufptr = buffer;
    char* outbufptr = outbuf;

    // convert as many charachters as possible
    log_debug("iconv(...) " << inbytesleft << " bytes");
    bool iconv_ret = conv.convert(&inbufptr, &inbytesleft,
          &outbufptr, &outbytesleft);

    pos += inbufptr - buffer;
    iconv_ret = iconv_ret || errno == EINVAL || errno == E2BIG;

    log_debug("pass " << outbufptr - outbuf << " bytes to sink");
    sink->write(outbuf, outbufptr - outbuf);

    if (sink->fail())
    {
      log_warn("sink failed");
      return traits_type::eof();
    }

    log_debug("reinitialize put area");
    setp(buffer, buffer + (sizeof(buffer) - 1));

    if (!iconv_ret) {
      switch (mode) {
        case iconvstreambuf::mode_skip:
          log_warn("convert failed, skipping byte");
          --inbytesleft;
          ++inbufptr;
          iconv_ret = true;
        break;
        case iconvstreambuf::mode_throw:
          log_warn("convert failed, throwing exception");
          throw iconv_error(pos);
        default:
          return traits_type::eof();
      }
    }

    // move left bytes to the start of buffer and reinitialize buffer
    if (inbytesleft > 0)
    {
      log_debug("move " << inbytesleft << " bytes to the start");
      sputn(inbufptr, inbytesleft);
    }

    return 0;
  }
}

iconvstream::int_type iconvstreambuf::underflow()
{
  log_warn("underflow not supported in iconvstreambuf");
  return traits_type::eof();
}

int iconvstreambuf::sync()
{
  log_debug("sync");

  if (pptr() == 0 || pptr() == buffer)
    return 0;
  else if (sink)
  {
    size_t ob, ob2;
    int_type ret;
    do
    {
      ob = pptr() - buffer;
      ret = overflow(traits_type::eof());
      ob2 = pptr() - buffer;
    } while (ob2 > 0 && ob2 < ob);

    log_debug("flush sink");
    sink->flush();

    return ret == traits_type::eof() || sink->fail() ? -1 : 0;
  }
  else
  {
    log_warn("no sink");
    return 0;
  }
}

std::streampos iconvstreambuf::seekoff(std::streamoff off,
  std::ios_base::seekdir way, std::ios_base::openmode which)
{
  // modify off to by relative position from current position
  switch (way) {
    case std::ios_base::beg:
      off -= pos;
    case std::ios_base::cur:
      break;
    default:
      return std::streampos(-1);
  }

  if (which == std::ios_base::in) {
    char *buf_p = gptr() + off;
    // alow seek only on valid data
    if (buf_p < eback() || buf_p > pptr())
        return std::streampos(-1);

    gbump(off);
    pos += off;
    return pos;
  }

  if (which == std::ios_base::out) {
    char *buf_p = pptr() + off;
    // alow seek only on valid data
    if (buf_p < pbase() || buf_p > pptr())
        return std::streampos(-1);

    pbump(off);
    return pos + off;
  }

  return std::streampos(-1);
}

std::streampos iconvstreambuf::seekpos(std::streampos sp,
  std::ios_base::openmode which)
{
  return seekoff(sp, std::ios_base::beg, which);
}

void iconvstream::open(std::ostream& sink_,
  const char* tocode, const char* fromcode)
{
  open(sink_, tocode, fromcode, iconvstreambuf::mode_default);
}

void iconvstream::open(std::ostream& sink_,
  const char* tocode, const char* fromcode,
  iconvstreambuf::mode_t mode)
{
  if (!fail() && streambuf.open(sink_, tocode, fromcode, mode) == 0)
    setstate(std::ios::failbit);
}

}
<|endoftext|>