<commit_before>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

#include <regex>
#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        class Response {
            friend class ServerBase<socket_type>;
        private:
            std::shared_ptr<boost::asio::strand> strand;

            boost::asio::yield_context& yield;

            boost::asio::streambuf streambuf;

            std::shared_ptr<socket_type> socket;

            std::shared_ptr<boost::asio::deadline_timer> async_timer;

            std::shared_ptr<bool> async_writing;
            std::shared_ptr<bool> async_waiting;

            Response(boost::asio::io_service& io_service, std::shared_ptr<socket_type> socket, std::shared_ptr<boost::asio::strand> strand,
                    boost::asio::yield_context& yield):
                    strand(strand), yield(yield), socket(socket), async_timer(new boost::asio::deadline_timer(io_service)),
                    async_writing(new bool(false)), async_waiting(new bool(false)), stream(&streambuf) {}

            void async_flush(std::function<void(const boost::system::error_code&)> callback=nullptr) {
                if(!callback && !socket->lowest_layer().is_open()) {
                    if(*async_waiting)
                        async_timer->cancel();
                    throw std::runtime_error("Broken pipe.");
                }

                std::shared_ptr<boost::asio::streambuf> write_buffer(new boost::asio::streambuf);
                std::ostream response(write_buffer.get());
                response << stream.rdbuf();

                //Wait until previous async_flush is finished
                strand->dispatch([this](){
                    if(*async_writing) {
                        *async_waiting=true;
                        try {
                            async_timer->async_wait(yield);
                        }
                        catch(std::exception& e) {
                        }
                        *async_waiting=false;
                    }
                });

                *async_writing=true;

                auto socket_=this->socket;
                auto async_writing_=this->async_writing;
                auto async_timer_=this->async_timer;
                auto async_waiting_=this->async_waiting;

                boost::asio::async_write(*socket, *write_buffer,
                        strand->wrap([socket_, write_buffer, callback, async_writing_, async_timer_, async_waiting_]
                        (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                    *async_writing_=false;
                    if(*async_waiting_)
                        async_timer_->cancel();
                    if(callback)
                        callback(ec);
                }));
            }

            void flush() {
                boost::asio::streambuf write_buffer;
                std::ostream response(&write_buffer);
                response << stream.rdbuf();

                boost::asio::async_write(*socket, write_buffer, yield);
            }

        public:
            std::ostream stream;

            template <class T>
            Response& operator<<(const T& t) {
                stream << t;
                return *this;
            }

            Response& operator<<(std::ostream& (*manip)(std::ostream&)) {
                stream << manip;
                return *this;
            }

            Response& operator<<(Response& (*manip)(Response&)) {
                return manip(*this);
            }
        };

        static Response& async_flush(Response& r) {
            r.async_flush();
            return r;
        }

        static Response& flush(Response& r) {
            r.flush();
            return r;
        }

        class Request {
            friend class ServerBase<socket_type>;
        public:
            std::string method, path, http_version;

            std::istream content;

            std::unordered_multimap<std::string, std::string> header;

            std::smatch path_match;

            std::string remote_endpoint_address;
            unsigned short remote_endpoint_port;

        private:
            Request(): content(&streambuf) {}

            boost::asio::streambuf streambuf;

            void read_remote_endpoint_data(socket_type& socket) {
                try {
                    remote_endpoint_address=socket.lowest_layer().remote_endpoint().address().to_string();
                    remote_endpoint_port=socket.lowest_layer().remote_endpoint().port();
                }
                catch(const std::exception& e) {
                    std::cerr << e.what() << std::endl;
                }
            }
        };

        std::unordered_map<std::string, std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > >  resource;

        std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;

    private:
        std::vector<std::pair<std::string, std::vector<std::pair<std::regex,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;

    public:
        void start() {
            //Copy the resources to opt_resource for more efficient request processing
            opt_resource.clear();
            for(auto& res: resource) {
                for(auto& res_method: res.second) {
                    auto it=opt_resource.end();
                    for(auto opt_it=opt_resource.begin();opt_it!=opt_resource.end();opt_it++) {
                        if(res_method.first==opt_it->first) {
                            it=opt_it;
                            break;
                        }
                    }
                    if(it==opt_resource.end()) {
                        opt_resource.emplace_back();
                        it=opt_resource.begin()+(opt_resource.size()-1);
                        it->first=res_method.first;
                    }
                    it->second.emplace_back(std::regex(res.first), res_method.second);
                }
            }

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            threads.clear();
            for(size_t c=1;c<num_threads;c++) {
                threads.emplace_back([this](){
                    io_service.run();
                });
            }

            //Main thread
            io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

        void stop() {
            io_service.stop();
        }

    protected:
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::endpoint endpoint;
        boost::asio::ip::tcp::acceptor acceptor;
        size_t num_threads;
        std::vector<std::thread> threads;

        size_t timeout_request;
        size_t timeout_content;

        ServerBase(unsigned short port, size_t num_threads, size_t timeout_request, size_t timeout_send_or_receive) :
                endpoint(boost::asio::ip::tcp::v4(), port), acceptor(io_service, endpoint), num_threads(num_threads),
                timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            });
            return timer;
        }

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, std::shared_ptr<boost::asio::strand> strand, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait(strand->wrap([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            }));
            return timer;
        }

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());
            request->read_remote_endpoint_data(*socket);

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->streambuf.size()-bytes_transferred;

                    parse_request(request, request->content);

                    //If content, read that as well
                    const auto it=request->header.find("Content-Length");
                    if(it!=request->header.end()) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);
                        try {
                            auto content_length=stoull(it->second);
                            boost::asio::async_read(*socket, request->streambuf,
                                    boost::asio::transfer_exactly(stoull(it->second)-num_additional_bytes),
                                    [this, socket, request, timer]
                                    (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                                if(timeout_content>0)
                                    timer->cancel();
                                if(!ec)
                                    find_resource(socket, request);
                            });
                        }
                        catch(const std::exception& e) {
                            std::cerr << e.what() << std::endl;
                        }
                    }
                    else {
                        find_resource(socket, request);
                    }
                }
            });
        }

        void parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::string line;
            getline(stream, line);
            size_t method_end=line.find(' ');
            size_t path_end=line.find(' ', method_end+1);
            if(method_end!=std::string::npos && path_end!=std::string::npos) {
                request->method=line.substr(0, method_end);
                request->path=line.substr(method_end+1, path_end-method_end-1);
                request->http_version=line.substr(path_end+6, line.size()-path_end-7);

                getline(stream, line);
                size_t param_end=line.find(':');
                while(param_end!=std::string::npos) {
                    size_t value_start=param_end+1;
                    if(line[value_start]==' ')
                        value_start++;

                    std::string key=line.substr(0, param_end);
                    request->header.insert(std::make_pair(key, line.substr(value_start, line.size()-value_start-1)));

                    getline(stream, line);
                    param_end=line.find(':');
                }
            }
        }

        void find_resource(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and call write_response
            for(auto& res: opt_resource) {
                if(request->method==res.first) {
                    for(auto& res_path: res.second) {
                        std::smatch sm_res;
                        if(std::regex_match(request->path, sm_res, res_path.first)) {
                            request->path_match=std::move(sm_res);
                            write_response(socket, request, res_path.second);
                            return;
                        }
                    }
                }
            }
            auto it_method=default_resource.find(request->method);
            if(it_method!=default_resource.end()) {
                write_response(socket, request, it_method->second);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request,
                std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
            std::shared_ptr<boost::asio::strand> strand(new boost::asio::strand(io_service));

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_content>0)
                timer=set_timeout_on_socket(socket, strand, timeout_content);

            boost::asio::spawn(*strand, [this, strand, &resource_function, socket, request, timer](boost::asio::yield_context yield) {
                Response response(io_service, socket, strand, yield);

                try {
                    resource_function(response, request);
                }
                catch(std::exception& e) {
                    return;
                }

                response.async_flush([this, socket, request, timer](const boost::system::error_code& ec) {
                    if(timeout_content>0)
                        timer->cancel();
                    if(!ec && stof(request->http_version)>1.05)
                        read_request_and_content(socket);
                });
            });
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, size_t timeout_request=5, size_t timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {}

    private:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec){
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    boost::asio::ip::tcp::no_delay option(true);
                    socket->set_option(option);

                    read_request_and_content(socket);
                }
            });
        }
    };
}
#endif	/* SERVER_HTTP_HPP */
<commit_msg>Minor fix.<commit_after>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

#include <regex>
#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        class Response {
            friend class ServerBase<socket_type>;
        private:
            std::shared_ptr<boost::asio::strand> strand;

            boost::asio::yield_context& yield;

            boost::asio::streambuf streambuf;

            std::shared_ptr<socket_type> socket;

            std::shared_ptr<boost::asio::deadline_timer> async_timer;

            std::shared_ptr<bool> async_writing;
            std::shared_ptr<bool> async_waiting;

            Response(boost::asio::io_service& io_service, std::shared_ptr<socket_type> socket, std::shared_ptr<boost::asio::strand> strand,
                    boost::asio::yield_context& yield):
                    strand(strand), yield(yield), socket(socket), async_timer(new boost::asio::deadline_timer(io_service)),
                    async_writing(new bool(false)), async_waiting(new bool(false)), stream(&streambuf) {}

            void async_flush(std::function<void(const boost::system::error_code&)> callback=nullptr) {
                if(!callback && !socket->lowest_layer().is_open()) {
                    if(*async_waiting)
                        async_timer->cancel();
                    throw std::runtime_error("Broken pipe.");
                }

                std::shared_ptr<boost::asio::streambuf> write_buffer(new boost::asio::streambuf);
                std::ostream response(write_buffer.get());
                response << stream.rdbuf();

                //Wait until previous async_flush is finished
                strand->dispatch([this](){
                    if(*async_writing) {
                        *async_waiting=true;
                        try {
                            async_timer->async_wait(yield);
                        }
                        catch(std::exception& e) {
                        }
                        *async_waiting=false;
                    }
                });

                *async_writing=true;

                auto socket_=this->socket;
                auto async_writing_=this->async_writing;
                auto async_timer_=this->async_timer;
                auto async_waiting_=this->async_waiting;

                boost::asio::async_write(*socket, *write_buffer,
                        strand->wrap([socket_, write_buffer, callback, async_writing_, async_timer_, async_waiting_]
                        (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                    *async_writing_=false;
                    if(*async_waiting_)
                        async_timer_->cancel();
                    if(callback)
                        callback(ec);
                }));
            }

            void flush() {
                boost::asio::streambuf write_buffer;
                std::ostream response(&write_buffer);
                response << stream.rdbuf();

                boost::asio::async_write(*socket, write_buffer, yield);
            }

        public:
            std::ostream stream;

            template <class T>
            Response& operator<<(const T& t) {
                stream << t;
                return *this;
            }

            Response& operator<<(std::ostream& (*manip)(std::ostream&)) {
                stream << manip;
                return *this;
            }

            Response& operator<<(Response& (*manip)(Response&)) {
                return manip(*this);
            }
        };

        static Response& async_flush(Response& r) {
            r.async_flush();
            return r;
        }

        static Response& flush(Response& r) {
            r.flush();
            return r;
        }

        class Request {
            friend class ServerBase<socket_type>;
        public:
            std::string method, path, http_version;

            std::istream content;

            std::unordered_multimap<std::string, std::string> header;

            std::smatch path_match;

            std::string remote_endpoint_address;
            unsigned short remote_endpoint_port;

        private:
            Request(): content(&streambuf) {}

            boost::asio::streambuf streambuf;

            void read_remote_endpoint_data(socket_type& socket) {
                try {
                    remote_endpoint_address=socket.lowest_layer().remote_endpoint().address().to_string();
                    remote_endpoint_port=socket.lowest_layer().remote_endpoint().port();
                }
                catch(const std::exception& e) {
                    std::cerr << e.what() << std::endl;
                }
            }
        };

        std::unordered_map<std::string, std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > >  resource;

        std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;

    private:
        std::vector<std::pair<std::string, std::vector<std::pair<std::regex,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;

    public:
        void start() {
            //Copy the resources to opt_resource for more efficient request processing
            opt_resource.clear();
            for(auto& res: resource) {
                for(auto& res_method: res.second) {
                    auto it=opt_resource.end();
                    for(auto opt_it=opt_resource.begin();opt_it!=opt_resource.end();opt_it++) {
                        if(res_method.first==opt_it->first) {
                            it=opt_it;
                            break;
                        }
                    }
                    if(it==opt_resource.end()) {
                        opt_resource.emplace_back();
                        it=opt_resource.begin()+(opt_resource.size()-1);
                        it->first=res_method.first;
                    }
                    it->second.emplace_back(std::regex(res.first), res_method.second);
                }
            }

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            threads.clear();
            for(size_t c=1;c<num_threads;c++) {
                threads.emplace_back([this](){
                    io_service.run();
                });
            }

            //Main thread
            io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

        void stop() {
            io_service.stop();
        }

    protected:
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::endpoint endpoint;
        boost::asio::ip::tcp::acceptor acceptor;
        size_t num_threads;
        std::vector<std::thread> threads;

        size_t timeout_request;
        size_t timeout_content;

        ServerBase(unsigned short port, size_t num_threads, size_t timeout_request, size_t timeout_send_or_receive) :
                endpoint(boost::asio::ip::tcp::v4(), port), acceptor(io_service, endpoint), num_threads(num_threads),
                timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            });
            return timer;
        }

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, std::shared_ptr<boost::asio::strand> strand, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait(strand->wrap([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            }));
            return timer;
        }

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());
            request->read_remote_endpoint_data(*socket);

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->streambuf.size()-bytes_transferred;

                    parse_request(request, request->content);

                    //If content, read that as well
                    const auto it=request->header.find("Content-Length");
                    if(it!=request->header.end()) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);
                        try {
                            auto content_length=stoull(it->second);
                            boost::asio::async_read(*socket, request->streambuf,
                                    boost::asio::transfer_exactly(content_length-num_additional_bytes),
                                    [this, socket, request, timer]
                                    (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                                if(timeout_content>0)
                                    timer->cancel();
                                if(!ec)
                                    find_resource(socket, request);
                            });
                        }
                        catch(const std::exception& e) {
                            std::cerr << e.what() << std::endl;
                        }
                    }
                    else {
                        find_resource(socket, request);
                    }
                }
            });
        }

        void parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::string line;
            getline(stream, line);
            size_t method_end=line.find(' ');
            size_t path_end=line.find(' ', method_end+1);
            if(method_end!=std::string::npos && path_end!=std::string::npos) {
                request->method=line.substr(0, method_end);
                request->path=line.substr(method_end+1, path_end-method_end-1);
                request->http_version=line.substr(path_end+6, line.size()-path_end-7);

                getline(stream, line);
                size_t param_end=line.find(':');
                while(param_end!=std::string::npos) {
                    size_t value_start=param_end+1;
                    if(line[value_start]==' ')
                        value_start++;

                    std::string key=line.substr(0, param_end);
                    request->header.insert(std::make_pair(key, line.substr(value_start, line.size()-value_start-1)));

                    getline(stream, line);
                    param_end=line.find(':');
                }
            }
        }

        void find_resource(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and call write_response
            for(auto& res: opt_resource) {
                if(request->method==res.first) {
                    for(auto& res_path: res.second) {
                        std::smatch sm_res;
                        if(std::regex_match(request->path, sm_res, res_path.first)) {
                            request->path_match=std::move(sm_res);
                            write_response(socket, request, res_path.second);
                            return;
                        }
                    }
                }
            }
            auto it_method=default_resource.find(request->method);
            if(it_method!=default_resource.end()) {
                write_response(socket, request, it_method->second);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request,
                std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
            std::shared_ptr<boost::asio::strand> strand(new boost::asio::strand(io_service));

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_content>0)
                timer=set_timeout_on_socket(socket, strand, timeout_content);

            boost::asio::spawn(*strand, [this, strand, &resource_function, socket, request, timer](boost::asio::yield_context yield) {
                Response response(io_service, socket, strand, yield);

                try {
                    resource_function(response, request);
                }
                catch(std::exception& e) {
                    return;
                }

                response.async_flush([this, socket, request, timer](const boost::system::error_code& ec) {
                    if(timeout_content>0)
                        timer->cancel();
                    if(!ec && stof(request->http_version)>1.05)
                        read_request_and_content(socket);
                });
            });
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, size_t timeout_request=5, size_t timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {}

    private:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec){
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    boost::asio::ip::tcp::no_delay option(true);
                    socket->set_option(option);

                    read_request_and_content(socket);
                }
            });
        }
    };
}
#endif	/* SERVER_HTTP_HPP */
<|endoftext|>


<commit_before>/*
** Copyright 2009-2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include <string.h>
#include "com/centreon/broker/neb/log_entry.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/neb/internal.hh"
#include "com/centreon/broker/neb/set_log_data.hh"

using namespace com::centreon::broker;

/**
 *  Extract the first element of a log string.
 */
static char* log_extract_first(char* str, char** lasts) {
  char* data(strtok_r(str, ";", lasts));
  if (!data)
    throw (exceptions::msg() << "log: data extraction failed");
  return (data);
}

/**
 *  Extract following elements of a log string.
 */
static char* log_extract(char** lasts) {
  char* data(strtok_r(NULL, ";", lasts));
  if (!data)
    throw (exceptions::msg() << "log: data extraction failed");
  return (data);
}

/**
 *  Get the id of a log status.
 */
static int status_id(char const* status) {
  int id;
  if (!strcmp(status, "DOWN") || !strcmp(status, "WARNING"))
    id = 1;
  else if (!strcmp(status, "UNREACHABLE") || !strcmp(status, "CRITICAL"))
    id = 2;
  else if (!strcmp(status, "UNKNOWN"))
    id = 3;
  else if (!strcmp(status, "PENDING"))
    id = 4;
  else
    id = 0;
  return (id);
}

/**
 *  Get the id of a log type.
 */
static int type_id(char const* type) {
  int id;
  if (!strcmp(type, "HARD"))
    id = 1;
  else
    id = 0;
  return (id);
}

/**
 *  Extract Nagios-formated log data to the C++ object.
 */
void neb::set_log_data(neb::log_entry& le, char const* log_data) {
  // Duplicate string so that we can split it with strtok_r.
  char* datadup(strdup(log_data));
  if (!datadup)
    throw (exceptions::msg() << "log: data extraction failed");

  try {
    char* lasts;

    // First part is the log description.
    lasts = datadup + strcspn(datadup, ":");
    if (*lasts) {
      *lasts = '\0';
      lasts = lasts + 1 + strspn(lasts + 1, " ");
    }
    if (!strcmp(datadup, "SERVICE ALERT")) {
      le.msg_type = 0;
      le.host_name = log_extract_first(lasts, &lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "HOST ALERT")) {
      le.msg_type = 1;
      le.host_name = log_extract_first(lasts, &lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "SERVICE NOTIFICATION")) {
      le.msg_type = 2;
      le.notification_contact = log_extract_first(lasts, &lasts);
      le.host_name = log_extract(&lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.notification_cmd = log_extract(&lasts);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "HOST NOTIFICATION")) {
      le.msg_type = 3;
      le.notification_contact = log_extract_first(lasts, &lasts);
      le.host_name = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.notification_cmd = log_extract(&lasts);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "CURRENT SERVICE STATE")) {
      le.msg_type = 6;
      le.host_name = log_extract_first(lasts, &lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "CURRENT HOST STATE")) {
      le.msg_type = 7;
      le.host_name = log_extract_first(lasts, &lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "INITIAL HOST STATE")) {
      le.msg_type = 9;
      le.host_name = log_extract_first(lasts, &lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "INITIAL SERVICE STATE")) {
      le.msg_type = 8;
      le.host_name = log_extract_first(lasts, &lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "EXTERNAL COMMAND")) {
      char* data(log_extract_first(lasts, &lasts));
      if (!strcmp(data, "ACKNOWLEDGE_SVC_PROBLEM")) {
        le.msg_type = 10;
        le.host_name = log_extract(&lasts);
        le.service_description = log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        le.notification_contact = log_extract(&lasts);
        le.output = log_extract(&lasts);
      }
      else if (!strcmp(data, "ACKNOWLEDGE_HOST_PROBLEM")) {
        le.msg_type = 11;
        le.host_name = log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        le.notification_contact = log_extract(&lasts);
        le.output = log_extract(&lasts);
      }
      else
        // XXX : seems like it should be something else ...
        throw (exceptions::msg() << "log: data extraction failed");
    }
    else if (!strcmp(datadup, "Warning")) {
      le.msg_type = 4;
      le.output = lasts;
    }
    else {
      le.msg_type = 5;
      le.output = log_data;
    }
  }
  catch (...) {}
  free(datadup);

  // Set host and service IDs.
  std::map<std::string, int>::const_iterator host_it;
  std::map<std::pair<std::string, std::string>, std::pair<int, int> >::const_iterator service_it;
  host_it = neb::gl_hosts.find(le.host_name.toStdString());
  if (host_it != neb::gl_hosts.end())
    le.host_id = host_it->second;
  service_it = neb::gl_services.find(std::make_pair(le.host_name.toStdString(),
    le.service_description.toStdString()));
  if (service_it != neb::gl_services.end()) {
    le.host_id = service_it->second.first;
    le.service_id = service_it->second.second;
  }

  return ;
}
<commit_msg>Fix log entries of external commands.<commit_after>/*
** Copyright 2009-2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include <string.h>
#include "com/centreon/broker/neb/log_entry.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/neb/internal.hh"
#include "com/centreon/broker/neb/set_log_data.hh"

using namespace com::centreon::broker;

/**
 *  Extract the first element of a log string.
 */
static char* log_extract_first(char* str, char** lasts) {
  char* data(strtok_r(str, ";", lasts));
  if (!data)
    throw (exceptions::msg() << "log: data extraction failed");
  return (data);
}

/**
 *  Extract following elements of a log string.
 */
static char* log_extract(char** lasts) {
  char* data(strtok_r(NULL, ";", lasts));
  if (!data)
    throw (exceptions::msg() << "log: data extraction failed");
  return (data);
}

/**
 *  Get the id of a log status.
 */
static int status_id(char const* status) {
  int id;
  if (!strcmp(status, "DOWN") || !strcmp(status, "WARNING"))
    id = 1;
  else if (!strcmp(status, "UNREACHABLE") || !strcmp(status, "CRITICAL"))
    id = 2;
  else if (!strcmp(status, "UNKNOWN"))
    id = 3;
  else if (!strcmp(status, "PENDING"))
    id = 4;
  else
    id = 0;
  return (id);
}

/**
 *  Get the id of a log type.
 */
static int type_id(char const* type) {
  int id;
  if (!strcmp(type, "HARD"))
    id = 1;
  else
    id = 0;
  return (id);
}

/**
 *  Extract Nagios-formated log data to the C++ object.
 */
void neb::set_log_data(neb::log_entry& le, char const* log_data) {
  // Duplicate string so that we can split it with strtok_r.
  char* datadup(strdup(log_data));
  if (!datadup)
    throw (exceptions::msg() << "log: data extraction failed");

  try {
    char* lasts;

    // First part is the log description.
    lasts = datadup + strcspn(datadup, ":");
    if (*lasts) {
      *lasts = '\0';
      lasts = lasts + 1 + strspn(lasts + 1, " ");
    }
    if (!strcmp(datadup, "SERVICE ALERT")) {
      le.msg_type = 0;
      le.host_name = log_extract_first(lasts, &lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "HOST ALERT")) {
      le.msg_type = 1;
      le.host_name = log_extract_first(lasts, &lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "SERVICE NOTIFICATION")) {
      le.msg_type = 2;
      le.notification_contact = log_extract_first(lasts, &lasts);
      le.host_name = log_extract(&lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.notification_cmd = log_extract(&lasts);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "HOST NOTIFICATION")) {
      le.msg_type = 3;
      le.notification_contact = log_extract_first(lasts, &lasts);
      le.host_name = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.notification_cmd = log_extract(&lasts);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "CURRENT SERVICE STATE")) {
      le.msg_type = 6;
      le.host_name = log_extract_first(lasts, &lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "CURRENT HOST STATE")) {
      le.msg_type = 7;
      le.host_name = log_extract_first(lasts, &lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "INITIAL HOST STATE")) {
      le.msg_type = 9;
      le.host_name = log_extract_first(lasts, &lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "INITIAL SERVICE STATE")) {
      le.msg_type = 8;
      le.host_name = log_extract_first(lasts, &lasts);
      le.service_description = log_extract(&lasts);
      le.status = status_id(log_extract(&lasts));
      le.log_type = type_id(log_extract(&lasts));
      le.retry = strtol(log_extract(&lasts), NULL, 10);
      le.output = log_extract(&lasts);
    }
    else if (!strcmp(datadup, "EXTERNAL COMMAND")) {
      char* data(log_extract_first(lasts, &lasts));
      if (!strcmp(data, "ACKNOWLEDGE_SVC_PROBLEM")) {
        le.msg_type = 10;
        le.host_name = log_extract(&lasts);
        le.service_description = log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        le.notification_contact = log_extract(&lasts);
        le.output = log_extract(&lasts);
      }
      else if (!strcmp(data, "ACKNOWLEDGE_HOST_PROBLEM")) {
        le.msg_type = 11;
        le.host_name = log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        log_extract(&lasts);
        le.notification_contact = log_extract(&lasts);
        le.output = log_extract(&lasts);
      }
      else {
        le.msg_type = 5;
        le.output = "EXTERNAL COMMAND: ";
        le.output.append(lasts);
      }
    }
    else if (!strcmp(datadup, "Warning")) {
      le.msg_type = 4;
      le.output = lasts;
    }
    else {
      le.msg_type = 5;
      le.output = log_data;
    }
  }
  catch (...) {}
  free(datadup);

  // Set host and service IDs.
  std::map<std::string, int>::const_iterator host_it;
  std::map<std::pair<std::string, std::string>, std::pair<int, int> >::const_iterator service_it;
  host_it = neb::gl_hosts.find(le.host_name.toStdString());
  if (host_it != neb::gl_hosts.end())
    le.host_id = host_it->second;
  service_it = neb::gl_services.find(std::make_pair(le.host_name.toStdString(),
    le.service_description.toStdString()));
  if (service_it != neb::gl_services.end()) {
    le.host_id = service_it->second.first;
    le.service_id = service_it->second.second;
  }

  return ;
}
<|endoftext|>


<commit_before>/// HEADER
#include "svm_array_trainer.h"

/// PROJECT
#include <csapex/msg/io.h>
#include <csapex/utility/register_apex_plugin.h>
#include <csapex/param/parameter_factory.h>
#include <csapex/model/node_modifier.h>
#include <csapex/msg/generic_vector_message.hpp>

CSAPEX_REGISTER_CLASS(csapex::SVMArrayTrainer, csapex::Node)

using namespace csapex;
using namespace csapex::connection_types;

template<typename T>
inline std::string toString(const T value)
{
    std::stringstream ss;
    ss << value;
    return ss.str();
}

struct ExtendedSVM : public cv::SVM {
    typedef std::shared_ptr<ExtendedSVM> Ptr;

    CvSVMDecisionFunc* get_decision_function()
    {
        return decision_func;
    }

    void print_decision_func()
    {
        std::cout << "alpha: [";
        for(int i = 0 ; i < decision_func->sv_count - 1; ++i) {
            std::cout << decision_func->alpha[i] << ", ";
        }
        std::cout << decision_func->alpha[decision_func->sv_count - 1]
                  << "]" << std::endl;
        std::cout << "rho: " << decision_func->rho  * -1 << std::endl;
    }

    void export_decision_func(cv::FileStorage &fs)
    {
        fs << "svm_alpha" << "[";
        for(int i = 0 ; i < decision_func->sv_count ; ++i)
            fs << decision_func->alpha[i];
        fs << "]";
        fs << "svm_rho" << -decision_func->rho;
    }

    void set_parameters(const cv::SVMParams &params)
    {
        set_params(params);
    }

};

SVMArrayTrainer::SVMArrayTrainer()
{
}

void SVMArrayTrainer::setupParameters(Parameterizable& parameters)
{
    CollectionNode<connection_types::FeaturesMessage>::setupParameters(parameters);

    parameters.addParameter(param::ParameterFactory::declareFileOutputPath("svm/path",
                                                                           param::ParameterDescription("File to write svm to."),
                                                                           "",
                                                                           "*.yaml *.tar.gz"),
                 path_);

    parameters.addParameter(param::ParameterFactory::declareBool("svm/save_coeffs",
                                                      param::ParameterDescription("Save precomputed vector for HOG."),
                                                      false),
                 save_for_hog_);

    std::map<std::string, int> kernel_types = {
        {"LINEAR", cv::SVM::LINEAR},
        {"POLY", cv::SVM::POLY},
        {"RBF", cv::SVM::RBF},
        {"SIGMOID", cv::SVM::SIGMOID}
    };

    parameters.addParameter(param::ParameterFactory::declareParameterSet("svm/kernel_type",
                                                                         csapex::param::ParameterDescription("Kernel type to be trained."),
                                                                         kernel_types,
                                                                         (int) cv::SVM::RBF),
                            svm_params_.kernel_type);

    std::map<std::string, int> svm_types = {
        {"C_SVC", cv::SVM::C_SVC},
        {"NU_SVC", cv::SVM::NU_SVC},
        {"ONE_CLASS", cv::SVM::ONE_CLASS},
        {"EPS_SVR", cv::SVM::EPS_SVR},
        {"NU_SVR", cv::SVM::NU_SVR}
    };

    parameters.addParameter(param::ParameterFactory::declareParameterSet("svm type",
                                                                         csapex::param::ParameterDescription("SVM type to be trained."),
                                                                         svm_types,
                                                                         (int) cv::SVM::EPS_SVR),
                            svm_params_.svm_type);

    std::function<bool()> deg_cond    = [this]() {
            return svm_params_.kernel_type == cv::SVM::POLY;};

    std::function<bool()> gamma_cond  = [this]() {
            return svm_params_.kernel_type == cv::SVM::POLY ||
                   svm_params_.kernel_type == cv::SVM::RBF ||
                   svm_params_.kernel_type == cv::SVM::SIGMOID;};

    std::function<bool()> coeff0_cond = [this]() {
            return svm_params_.kernel_type == cv::SVM::POLY ||
                   svm_params_.kernel_type == cv::SVM::SIGMOID;};

    std::function<bool()> c_cond = [this]() {
            return svm_params_.svm_type == cv::SVM::C_SVC ||
                   svm_params_.svm_type == cv::SVM::EPS_SVR ||
                   svm_params_.svm_type == cv::SVM::NU_SVR;};

    std::function<bool()> nu_cond = [this]() {
            return svm_params_.svm_type == cv::SVM::ONE_CLASS ||
                   svm_params_.svm_type == cv::SVM::NU_SVR ||
                   svm_params_.svm_type == cv::SVM::EPS_SVR;};

    std::function<bool()> p_cond = [this]() {
            return svm_params_.svm_type == cv::SVM::EPS_SVR;};

    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("degree", 0.0, 9.0, 3.0, 1.0),
                                       deg_cond,
                                       svm_params_.degree);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("gamma", 0.0, 10.0, 0.0, 0.01),
                                       gamma_cond,
                                       svm_params_.gamma);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("coef0", -10.0, 10.0, 0.0, 0.01),
                                       coeff0_cond,
                                       svm_params_.coef0);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("C", 0.0, 10.0, 0.01, 0.01),
                                       c_cond,
                                       svm_params_.C);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("nu", 0.0, 1.0, 0.5, 0.01),
                                       nu_cond,
                                       svm_params_.nu);
    parameters.addConditionalParameter(csapex::param::ParameterFactory::declareRange<double>("p", 0.0, 1.0, 0.1, 0.01),
                                       p_cond,
                                       svm_params_.p);
}

void SVMArrayTrainer::processCollection(std::vector<FeaturesMessage> &collection)
{
    /// TODO : Mix classes for negative samples?

    if(collection.empty())
        return;

    std::size_t step = collection.front().value.size();
    std::map<int, std::vector<std::size_t>> indices_by_label;

    for(std::size_t i = 0 ; i < collection.size() ; ++i) {
        const FeaturesMessage &fm = collection[i];
        if(fm.value.size() != step)
            throw std::runtime_error("All descriptors must have the same length!");
        indices_by_label[fm.classification].push_back(i);
    }

    std::map<int, ExtendedSVM::Ptr> svms;
    if(svm_params_.svm_type != cv::SVM::ONE_CLASS) {
        if(indices_by_label.find(NEGATIVE) == indices_by_label.end()) {
            throw std::runtime_error("Need negative examples labelled with -1");
        }
        if(indices_by_label.size() == 1) {
            throw std::runtime_error("Multi class SVMs require multiple classes!");
        }
        std::vector<std::size_t> neg_indices = indices_by_label[NEGATIVE];
        indices_by_label.erase(NEGATIVE);
        /// iterate samples
        for(std::size_t i = 0 ; i < indices_by_label.size() ; ++i) {
            auto it = indices_by_label.begin();
            std::advance(it, i);

            /// allocate svm
            ExtendedSVM::Ptr svm(new ExtendedSVM);
            svms[it->first] = svm;

            /// gather data
            const std::vector<std::size_t> &pos_indices = it->second;
            const std::size_t sample_size = pos_indices.size() + neg_indices.size();

            cv::Mat samples(sample_size, step, CV_32FC1, cv::Scalar());
            cv::Mat labels(sample_size, 1, CV_32FC1, cv::Scalar());

            cv::Mat neg_samples = samples.rowRange(0, neg_indices.size());
            cv::Mat pos_samples = samples.rowRange(neg_indices.size(), sample_size);
            cv::Mat neg_labels = labels.rowRange(0, neg_indices.size());
            cv::Mat pos_labels = labels.rowRange(neg_indices.size(), sample_size);
            for(int i = 0 ; i < neg_samples.rows; ++i) {
                const std::vector<float> &data = collection.at(neg_indices.at(i)).value;
                neg_labels.at<float>(i) = NEGATIVE;
                for(std::size_t j = 0 ; j < step ; ++j) {
                    neg_samples.at<float>(i,j) = data.at(j);
                }
            }
            for(int i = 0 ; i < pos_samples.rows ; ++i) {
                const std::vector<float> &data = collection.at(pos_indices.at(i)).value;
                pos_labels.at<float>(i) = POSITIVE;
                for(std::size_t j = 0 ; j < step ; ++j) {
                    pos_samples.at<float>(i,j) = data.at(j);
                }
            }
            cv::SVMParams params = svm_params_;
            if(params.gamma == 0) {
                params.gamma = 1.0 / labels.rows;
            }

            /// train the svm
            std::cout << "Started training for '" << it->first << std::endl;
            svm.reset(new ExtendedSVM);
            if(svm->train(samples, labels, cv::Mat(), cv::Mat(), params)) {
                std::cout << "Finished training for '" << it->first << std::endl;
            }
        }
    } else {
        if(indices_by_label.find(NEGATIVE) != indices_by_label.end()) {
            indices_by_label.erase(NEGATIVE);
        }
        /// iterate samples
        /// mixed classes?
        for(std::size_t i = 0 ; i < indices_by_label.size() ; ++i) {
            auto it = indices_by_label.begin();
            std::advance(it, i);

            /// allocate svm
            ExtendedSVM::Ptr svm(new ExtendedSVM);
            svms[it->first] = svm;

            /// gather data
            const std::vector<std::size_t> &indices = it->second;
            const std::size_t sample_size = indices.size();

            cv::Mat samples(sample_size, step, CV_32FC1, cv::Scalar());
            cv::Mat labels(sample_size, 1, CV_32FC1, cv::Scalar());

            for(int i = 0 ; i < samples.rows ; ++i) {
                const std::vector<float> &data = collection.at(indices.at(i)).value;
                labels.at<float>(i) = POSITIVE;
                for(std::size_t j = 0 ; j < step ; ++j) {
                    samples.at<float>(i,j) = data.at(j);
                }
            }
            cv::SVMParams params = svm_params_;
            if(params.gamma == 0) {
                params.gamma = 1.0 / labels.rows;
            }

            /// train the svm
            std::cout << "Started training for '" << it->first << std::endl;
            svm.reset(new ExtendedSVM);
            if(svm->train(samples, labels, cv::Mat(), cv::Mat(), params)) {
                std::cout << "Finished training for '" << it->first << std::endl;
            }
        }

    }
    /// write all svms to disk
    cv::FileStorage fs(path_, cv::FileStorage::WRITE);
    const static std::string prefix = "svm_";
    std::vector<int> labels;
    for(auto &svm_entry : svms) {
        std::string label = prefix + toString(svm_entry.first);
        ExtendedSVM::Ptr svm = svm_entry.second;
        svm->write(fs.fs, label.c_str());
        labels.push_back(svm_entry.first);
    }
    fs << "labels" << labels;
    fs.release();
}
<commit_msg>svm array training works now<commit_after>/// HEADER
#include "svm_array_trainer.h"

/// PROJECT
#include <csapex/msg/io.h>
#include <csapex/utility/register_apex_plugin.h>
#include <csapex/param/parameter_factory.h>
#include <csapex/model/node_modifier.h>
#include <csapex/msg/generic_vector_message.hpp>

CSAPEX_REGISTER_CLASS(csapex::SVMArrayTrainer, csapex::Node)

using namespace csapex;
using namespace csapex::connection_types;

template<typename T>
inline std::string toString(const T value)
{
    std::stringstream ss;
    ss << value;
    return ss.str();
}

struct ExtendedSVM : public cv::SVM {
    typedef std::shared_ptr<ExtendedSVM> Ptr;

    CvSVMDecisionFunc* get_decision_function()
    {
        return decision_func;
    }

    void print_decision_func()
    {
        std::cout << "alpha: [";
        for(int i = 0 ; i < decision_func->sv_count - 1; ++i) {
            std::cout << decision_func->alpha[i] << ", ";
        }
        std::cout << decision_func->alpha[decision_func->sv_count - 1]
                  << "]" << std::endl;
        std::cout << "rho: " << decision_func->rho  * -1 << std::endl;
    }

    void export_decision_func(cv::FileStorage &fs)
    {
        fs << "svm_alpha" << "[";
        for(int i = 0 ; i < decision_func->sv_count ; ++i)
            fs << decision_func->alpha[i];
        fs << "]";
        fs << "svm_rho" << -decision_func->rho;
    }

    void set_parameters(const cv::SVMParams &params)
    {
        set_params(params);
    }

};

SVMArrayTrainer::SVMArrayTrainer()
{
}

void SVMArrayTrainer::setupParameters(Parameterizable& parameters)
{
    CollectionNode<connection_types::FeaturesMessage>::setupParameters(parameters);

    parameters.addParameter(param::ParameterFactory::declareFileOutputPath("svm/path",
                                                                           param::ParameterDescription("File to write svm to."),
                                                                           "",
                                                                           "*.yaml *.tar.gz"),
                 path_);

    parameters.addParameter(param::ParameterFactory::declareBool("svm/save_coeffs",
                                                      param::ParameterDescription("Save precomputed vector for HOG."),
                                                      false),
                 save_for_hog_);

    std::map<std::string, int> kernel_types = {
        {"LINEAR", cv::SVM::LINEAR},
        {"POLY", cv::SVM::POLY},
        {"RBF", cv::SVM::RBF},
        {"SIGMOID", cv::SVM::SIGMOID}
    };

    parameters.addParameter(param::ParameterFactory::declareParameterSet("svm/kernel_type",
                                                                         csapex::param::ParameterDescription("Kernel type to be trained."),
                                                                         kernel_types,
                                                                         (int) cv::SVM::RBF),
                            svm_params_.kernel_type);

    std::map<std::string, int> svm_types = {
        {"C_SVC", cv::SVM::C_SVC},
        {"NU_SVC", cv::SVM::NU_SVC},
        {"ONE_CLASS", cv::SVM::ONE_CLASS},
        {"EPS_SVR", cv::SVM::EPS_SVR},
        {"NU_SVR", cv::SVM::NU_SVR}
    };

    parameters.addParameter(param::ParameterFactory::declareParameterSet("svm type",
                                                                         csapex::param::ParameterDescription("SVM type to be trained."),
                                                                         svm_types,
                                                                         (int) cv::SVM::EPS_SVR),
                            svm_params_.svm_type);

    std::function<bool()> deg_cond    = [this]() {
            return svm_params_.kernel_type == cv::SVM::POLY;};

    std::function<bool()> gamma_cond  = [this]() {
            return svm_params_.kernel_type == cv::SVM::POLY ||
                   svm_params_.kernel_type == cv::SVM::RBF ||
                   svm_params_.kernel_type == cv::SVM::SIGMOID;};

    std::function<bool()> coeff0_cond = [this]() {
            return svm_params_.kernel_type == cv::SVM::POLY ||
                   svm_params_.kernel_type == cv::SVM::SIGMOID;};

    std::function<bool()> c_cond = [this]() {
            return svm_params_.svm_type == cv::SVM::C_SVC ||
                   svm_params_.svm_type == cv::SVM::EPS_SVR ||
                   svm_params_.svm_type == cv::SVM::NU_SVR;};

    std::function<bool()> nu_cond = [this]() {
            return svm_params_.svm_type == cv::SVM::ONE_CLASS ||
                   svm_params_.svm_type == cv::SVM::NU_SVR ||
                   svm_params_.svm_type == cv::SVM::EPS_SVR;};

    std::function<bool()> p_cond = [this]() {
            return svm_params_.svm_type == cv::SVM::EPS_SVR;};

    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("degree", 0.0, 9.0, 3.0, 1.0),
                                       deg_cond,
                                       svm_params_.degree);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("gamma", 0.0, 10.0, 0.0, 0.01),
                                       gamma_cond,
                                       svm_params_.gamma);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("coef0", -10.0, 10.0, 0.0, 0.01),
                                       coeff0_cond,
                                       svm_params_.coef0);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("C", 0.0, 10.0, 0.01, 0.01),
                                       c_cond,
                                       svm_params_.C);
    parameters.addConditionalParameter(param::ParameterFactory::declareRange<double>("nu", 0.0, 1.0, 0.5, 0.01),
                                       nu_cond,
                                       svm_params_.nu);
    parameters.addConditionalParameter(csapex::param::ParameterFactory::declareRange<double>("p", 0.0, 1.0, 0.1, 0.01),
                                       p_cond,
                                       svm_params_.p);
}

void SVMArrayTrainer::processCollection(std::vector<FeaturesMessage> &collection)
{
    /// TODO : Mix classes for negative samples?

    if(collection.empty())
        return;

    std::size_t step = collection.front().value.size();
    std::map<int, std::vector<std::size_t>> indices_by_label;

    for(std::size_t i = 0 ; i < collection.size() ; ++i) {
        const FeaturesMessage &fm = collection[i];
        if(fm.value.size() != step)
            throw std::runtime_error("All descriptors must have the same length!");
        indices_by_label[fm.classification].push_back(i);
    }

//    /// write all svms to disk
//    for(auto &svm_entry : svms) {
//    }

    std::vector<int> svm_labels;
    cv::FileStorage fs(path_, cv::FileStorage::WRITE);
    const static std::string prefix = "svm_";
    if(svm_params_.svm_type != cv::SVM::ONE_CLASS) {
        if(indices_by_label.find(NEGATIVE) == indices_by_label.end()) {
            throw std::runtime_error("Need negative examples labelled with -1");
        }
        if(indices_by_label.size() == 1) {
            throw std::runtime_error("Multi class SVMs require multiple classes!");
        }
        std::vector<std::size_t> neg_indices = indices_by_label[NEGATIVE];
        indices_by_label.erase(NEGATIVE);
        /// iterate samples
        for(std::size_t i = 0 ; i < indices_by_label.size() ; ++i) {
            auto it = indices_by_label.begin();
            std::advance(it, i);

            /// allocate svm
            ExtendedSVM svm;
            /// gather data
            const std::vector<std::size_t> &pos_indices = it->second;
            const std::size_t sample_size = pos_indices.size() + neg_indices.size();

            cv::Mat samples(sample_size, step, CV_32FC1, cv::Scalar());
            cv::Mat labels(sample_size, 1, CV_32FC1, cv::Scalar());

            cv::Mat neg_samples = samples.rowRange(0, neg_indices.size());
            cv::Mat pos_samples = samples.rowRange(neg_indices.size(), sample_size);
            cv::Mat neg_labels = labels.rowRange(0, neg_indices.size());
            cv::Mat pos_labels = labels.rowRange(neg_indices.size(), sample_size);
            for(int i = 0 ; i < neg_samples.rows; ++i) {
                const std::vector<float> &data = collection.at(neg_indices.at(i)).value;
                neg_labels.at<float>(i) = NEGATIVE;
                for(std::size_t j = 0 ; j < step ; ++j) {
                    neg_samples.at<float>(i,j) = data.at(j);
                }
            }
            for(int i = 0 ; i < pos_samples.rows ; ++i) {
                const std::vector<float> &data = collection.at(pos_indices.at(i)).value;
                pos_labels.at<float>(i) = POSITIVE;
                for(std::size_t j = 0 ; j < step ; ++j) {
                    pos_samples.at<float>(i,j) = data.at(j);
                }
            }
            cv::SVMParams params = svm_params_;
            if(params.gamma == 0) {
                params.gamma = 1.0 / labels.rows;
            }

            /// train the svm
            std::cout << "Started training for '" << it->first << std::endl;
            if(svm.train(samples, labels, cv::Mat(), cv::Mat(), params)) {
                std::cout << "Finished training for '" << it->first << "'!" << std::endl;
                std::string label = prefix + toString(it->first);
                svm.write(fs.fs, label.c_str());
                svm_labels.push_back(it->first);
            } else {
                std::cerr << "Failed traininng for '" << it->first << "'!" << std::endl;
            }
        }
    } else {
        if(indices_by_label.find(NEGATIVE) != indices_by_label.end()) {
            indices_by_label.erase(NEGATIVE);
        }
        /// iterate samples
        /// mixed classes?
        for(std::size_t i = 0 ; i < indices_by_label.size() ; ++i) {
            auto it = indices_by_label.begin();
            std::advance(it, i);

            /// allocate svm
            ExtendedSVM svm;

            /// gather data
            const std::vector<std::size_t> &indices = it->second;
            const std::size_t sample_size = indices.size();

            cv::Mat samples(sample_size, step, CV_32FC1, cv::Scalar());
            cv::Mat labels(sample_size, 1, CV_32FC1, cv::Scalar());

            for(int i = 0 ; i < samples.rows ; ++i) {
                const std::vector<float> &data = collection.at(indices.at(i)).value;
                labels.at<float>(i) = POSITIVE;
                for(std::size_t j = 0 ; j < step ; ++j) {
                    samples.at<float>(i,j) = data.at(j);
                }
            }
            cv::SVMParams params = svm_params_;
            if(params.gamma == 0) {
                params.gamma = 1.0 / labels.rows;
            }

            /// train the svm
            std::cout << "Started training for '" << it->first << std::endl;
            if(svm.train(samples, labels, cv::Mat(), cv::Mat(), params)) {
                std::cout << "Finished training for '" << it->first << std::endl;
                std::string label = prefix + toString(it->first);
                svm.write(fs.fs, label.c_str());
                svm_labels.push_back(it->first);
            } else {
                std::cerr << "Failed traininng for '" << it->first << "'!" << std::endl;
            }
        }
    }
    fs << "labels" << svm_labels;
    fs.release();

    //    /// write all svms to disk
//    cv::FileStorage fs(path_, cv::FileStorage::WRITE);
//    const static std::string prefix = "svm_";
//    std::vector<int> labels;
//    for(auto &svm_entry : svms) {
//        std::string label = prefix + toString(svm_entry.first);
//        ExtendedSVM::Ptr svm = svm_entry.second;
//        svm->write(fs.fs, label.c_str());
//        labels.push_back(svm_entry.first);
//    }
//    fs << "labels" << labels;
//    fs.release();
}
<|endoftext|>


<commit_before>/*
* Copyright (c) 2003-2009 Rony Shapiro <ronys@users.sourceforge.net>.
* All rights reserved. Use of the code is allowed under the
* Artistic License 2.0 terms, as specified in the LICENSE file
* distributed with this code, or available from
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/
/// \file Win32FaultHandler.cpp
//-----------------------------------------------------------------------------

// Only produce minidumps in release code

/*
 * Get everything set up now.
 * Use only standard Windows functions in FaultHandler
 *
 * *** *** *** *** ***
 *  NOTE: NO MFC CODE
 * *** *** *** *** ***
 */

#ifndef _DEBUG

#include "stdafx.h"

#include "resource3.h"

#include <stdio.h>
#include <sys/timeb.h>
#include <time.h>

#include "Dbghelp.h"

LONG Win32FaultHandler(struct _EXCEPTION_POINTERS *ExInfo);

static DWORD dwTimeStamp;
static int iMajor, iMinor, iBuild;
static wchar_t *wcRevision = NULL;

static wchar_t *wcMsg1 = NULL;
static wchar_t *wcMsg2 = NULL;
static wchar_t *wcMsg3 = NULL;
static wchar_t *wcCaption = NULL;

void InstallFaultHandler(const int major, const int minor, const int build,
                         const wchar_t *revision, const DWORD timestamp)
{
  iMajor = major;
  iMinor = minor;
  iBuild = build;
  wcRevision = _wcsdup(revision);
  dwTimeStamp = timestamp;

  // Set up message now - just in case!
  wchar_t wcBuffer[4096];

  LoadString(GetModuleHandle(NULL), IDS_MD_MSG1, wcBuffer, 4096);
  wcMsg1 = _wcsdup(wcBuffer);

  LoadString(GetModuleHandle(NULL), IDS_MD_MSG2, wcBuffer, 4096);
  wcMsg2 = _wcsdup(wcBuffer);

  LoadString(GetModuleHandle(NULL), IDS_MD_MSG3, wcBuffer, 4096);
  wcMsg3 = _wcsdup(wcBuffer);

  LoadString(GetModuleHandle(NULL), IDS_MD_CAPTION, wcBuffer, 4096);
  wcCaption = _wcsdup(wcBuffer);

  SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)Win32FaultHandler);
}

LONG Win32FaultHandler(struct _EXCEPTION_POINTERS *ExInfo)
{
  // Use standard functions as much as possible
  wchar_t szTempName[MAX_PATH + 1];

  wchar_t szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFName[_MAX_FNAME];
  wchar_t wcTempPath[4096];
  DWORD dwBufSize(4096);

  // Get the temp path
  DWORD dwrc = GetTempPathW(dwBufSize, wcTempPath);
  if (dwrc == 0 || dwrc > dwBufSize)
    goto exit;

  // Create a temporary file.
  struct tm xt;
  struct __timeb32 timebuffer;
  _ftime32_s(&timebuffer);
  localtime_s(&xt, &(timebuffer.time));

  _wsplitpath_s(wcTempPath, szDrive, _MAX_DRIVE, szDir, _MAX_DIR,
                           NULL, 0, NULL, 0);
  swprintf_s(szFName, _MAX_FNAME, L"PWS_Minidump_%04d%02d%02d_%02d%02d%02d%03d",
                  xt.tm_year + 1900, xt.tm_mon + 1, xt.tm_mday,
                  xt.tm_hour, xt.tm_min, xt.tm_sec, timebuffer.millitm);
  _wmakepath_s(szTempName, MAX_PATH + 1, szDrive, szDir, szFName, L"dmp");

  wchar_t szUserData[MAX_PATH];
  swprintf_s(szUserData, MAX_PATH, L"PasswordSafe V%d.%d.%d(%s). Module timestamp: %08x",
                  iMajor, iMinor, iBuild, wcRevision, dwTimeStamp);

  HANDLE hFile = CreateFile(szTempName, GENERIC_READ | GENERIC_WRITE,
                            0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  MINIDUMP_EXCEPTION_INFORMATION excpInfo;
  excpInfo.ClientPointers = FALSE;
  excpInfo.ExceptionPointers = ExInfo;
  excpInfo.ThreadId = GetCurrentThreadId();

  MINIDUMP_USER_STREAM UserStreams[1];

  UserStreams[0].Type = LastReservedStream + 1;
  UserStreams[0].Buffer = (void *)szUserData;
  UserStreams[0].BufferSize = sizeof(szUserData);

  MINIDUMP_USER_STREAM_INFORMATION musi;
  musi.UserStreamCount = 1;
  musi.UserStreamArray = UserStreams;

  MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
                    MiniDumpNormal, &excpInfo, &musi, NULL);

  CloseHandle(hFile);

  size_t len = wcslen(wcMsg1) + wcslen(szFName) + wcslen(wcMsg2) +
                   wcslen(wcTempPath) + wcslen(wcMsg3) + 3;
  wchar_t *sz_errormsg = (wchar_t *)malloc(len * sizeof(wchar_t));
  wcscpy_s(sz_errormsg, len, wcMsg1);
  wcscat_s(sz_errormsg, len, szFName);
  wcscat_s(sz_errormsg, len, wcMsg2);
  wcscat_s(sz_errormsg, len, wcTempPath);
  wcscat_s(sz_errormsg, len, wcMsg3);

  // Issue error message
  wchar_t szCaption[MAX_PATH];
  swprintf_s(szCaption, MAX_PATH, wcCaption,
                  iMajor, iMinor, iBuild, wcRevision);
  int irc = ::MessageBox(GetForegroundWindow(), sz_errormsg, szCaption,
                       MB_YESNO | MB_APPLMODAL | MB_ICONERROR);
  if (irc == IDNO)
    _wremove(szTempName);

  free(sz_errormsg);

  free(wcRevision);
  free(wcMsg1);
  free(wcMsg2);
  free(wcMsg3);
  free(wcCaption);

  wcRevision = NULL;
  wcMsg1 = NULL;
  wcMsg2 = NULL;
  wcMsg3 = NULL;
  wcCaption = NULL;

exit:
  return EXCEPTION_CONTINUE_SEARCH;
}

void RemoveFaultHandler()
{
  free(wcRevision);
  free(wcMsg1);
  free(wcMsg2);
  free(wcMsg3);
  free(wcCaption);

  wcRevision = NULL;
  wcMsg1 = NULL;
  wcMsg2 = NULL;
  wcMsg3 = NULL;
  wcCaption = NULL;

  SetUnhandledExceptionFilter(NULL);
}

#endif
<commit_msg>robust++ fault handling<commit_after>/*
* Copyright (c) 2003-2009 Rony Shapiro <ronys@users.sourceforge.net>.
* All rights reserved. Use of the code is allowed under the
* Artistic License 2.0 terms, as specified in the LICENSE file
* distributed with this code, or available from
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/
/// \file Win32FaultHandler.cpp
//-----------------------------------------------------------------------------

// Only produce minidumps in release code

/*
 * Get everything set up now.
 * Use only standard Windows functions in FaultHandler
 *
 * *** *** *** *** ***
 *  NOTE: NO MFC CODE
 * *** *** *** *** ***
 */

#ifndef _DEBUG

#include "stdafx.h"

#include "resource3.h"

#include <stdio.h>
#include <sys/timeb.h>
#include <time.h>

#include "Dbghelp.h"

LONG Win32FaultHandler(struct _EXCEPTION_POINTERS *ExInfo);
const int MSGSIZE = 1024; // use static arrays, in case heap gets corrupted

static DWORD dwTimeStamp;
static int iMajor, iMinor, iBuild;
static wchar_t wcRevision[MSGSIZE];

static wchar_t wcMsg1[MSGSIZE];
static wchar_t wcMsg2[MSGSIZE];
static wchar_t wcMsg3[MSGSIZE];
static wchar_t wcCaption[MSGSIZE];

void InstallFaultHandler(const int major, const int minor, const int build,
                         const wchar_t *revision, const DWORD timestamp)
{
  iMajor = major;
  iMinor = minor;
  iBuild = build;
  wcscpy_s(wcRevision, revision);
  dwTimeStamp = timestamp;

  // Set up message now - just in case!
  LoadString(GetModuleHandle(NULL), IDS_MD_MSG1, wcMsg1, MSGSIZE);
  LoadString(GetModuleHandle(NULL), IDS_MD_MSG2, wcMsg2, MSGSIZE);
  LoadString(GetModuleHandle(NULL), IDS_MD_MSG3, wcMsg3, MSGSIZE);
  LoadString(GetModuleHandle(NULL), IDS_MD_CAPTION, wcCaption, MSGSIZE);

  SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)Win32FaultHandler);
}

LONG Win32FaultHandler(struct _EXCEPTION_POINTERS *ExInfo)
{
  // Use standard functions as much as possible
  wchar_t szTempName[MAX_PATH + 1];

  wchar_t szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFName[_MAX_FNAME];
  wchar_t wcTempPath[4096];
  DWORD dwBufSize(4096);

  // Get the temp path
  DWORD dwrc = GetTempPathW(dwBufSize, wcTempPath);
  if (dwrc == 0 || dwrc > dwBufSize)
    goto exit;

  // Create a temporary file.
  struct tm xt;
  struct __timeb32 timebuffer;
  _ftime32_s(&timebuffer);
  localtime_s(&xt, &(timebuffer.time));

  _wsplitpath_s(wcTempPath, szDrive, _MAX_DRIVE, szDir, _MAX_DIR,
                NULL, 0, NULL, 0);
  swprintf_s(szFName, _MAX_FNAME, L"PWS_Minidump_%04d%02d%02d_%02d%02d%02d%03d",
             xt.tm_year + 1900, xt.tm_mon + 1, xt.tm_mday,
             xt.tm_hour, xt.tm_min, xt.tm_sec, timebuffer.millitm);
  _wmakepath_s(szTempName, MAX_PATH + 1, szDrive, szDir, szFName, L"dmp");

  wchar_t szUserData[MAX_PATH];
  swprintf_s(szUserData, MAX_PATH, L"PasswordSafe V%d.%d.%d(%s). Module timestamp: %08x",
             iMajor, iMinor, iBuild, wcRevision, dwTimeStamp);

  HANDLE hFile = CreateFile(szTempName, GENERIC_READ | GENERIC_WRITE,
                            0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile != INVALID_HANDLE_VALUE) {
    MINIDUMP_EXCEPTION_INFORMATION excpInfo;
    excpInfo.ClientPointers = FALSE;
    excpInfo.ExceptionPointers = ExInfo;
    excpInfo.ThreadId = GetCurrentThreadId();

    MINIDUMP_USER_STREAM UserStreams[1];

    UserStreams[0].Type = LastReservedStream + 1;
    UserStreams[0].Buffer = (void *)szUserData;
    UserStreams[0].BufferSize = sizeof(szUserData);

    MINIDUMP_USER_STREAM_INFORMATION musi;
    musi.UserStreamCount = 1;
    musi.UserStreamArray = UserStreams;

    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
                      MiniDumpNormal, &excpInfo, &musi, NULL);

    CloseHandle(hFile);

    size_t len = wcslen(wcMsg1) + wcslen(szFName) + wcslen(wcMsg2) +
      wcslen(wcTempPath) + wcslen(wcMsg3) + 3;
    wchar_t sz_errormsg[4*MSGSIZE]; // not a good place for malloc, as the heap
    //                                 may be corrupt...
    wcscpy_s(sz_errormsg, len, wcMsg1);
    wcscat_s(sz_errormsg, len, szFName);
    wcscat_s(sz_errormsg, len, wcMsg2);
    wcscat_s(sz_errormsg, len, wcTempPath);
    wcscat_s(sz_errormsg, len, wcMsg3);

    // Issue error message
    wchar_t szCaption[MAX_PATH];
    swprintf_s(szCaption, MAX_PATH, wcCaption, iMajor, iMinor, iBuild, wcRevision);
    int irc = ::MessageBox(GetForegroundWindow(), sz_errormsg, szCaption,
                           MB_YESNO | MB_APPLMODAL | MB_ICONERROR);
    if (irc == IDNO)
      _wremove(szTempName);
  } // valid file handle
 exit:
  return EXCEPTION_CONTINUE_SEARCH;
}

void RemoveFaultHandler()
{
  SetUnhandledExceptionFilter(NULL);
}
#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: xmlMasterFields.cxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#include "precompiled_reportdesign.hxx"
#include "xmlMasterFields.hxx"
#include "xmlfilter.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnmspe.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmlEnums.hxx"
#include "xmlReport.hxx"
#include <tools/debug.hxx>

namespace rptxml
{
    using namespace ::com::sun::star;
    using namespace ::com::sun::star::report;
    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::xml::sax;
DBG_NAME( rpt_OXMLMasterFields )

OXMLMasterFields::OXMLMasterFields( ORptFilter& rImport,
                sal_uInt16 nPrfx, const ::rtl::OUString& rLName,
                const Reference< XAttributeList > & _xAttrList
                ,IMasterDetailFieds* _pReport
                ) :
    SvXMLImportContext( rImport, nPrfx, rLName)
,m_pReport(_pReport)
{
    DBG_CTOR( rpt_OXMLMasterFields,NULL);

    const SvXMLNamespaceMap& rMap = rImport.GetNamespaceMap();
    const SvXMLTokenMap& rTokenMap = rImport.GetSubDocumentElemTokenMap();

    ::rtl::OUString sMasterField,sDetailField;
    const sal_Int16 nLength = (_xAttrList.is()) ? _xAttrList->getLength() : 0;
    for(sal_Int16 i = 0; i < nLength; ++i)
    {
     ::rtl::OUString sLocalName;
        const rtl::OUString sAttrName = _xAttrList->getNameByIndex( i );
        const sal_uInt16 nPrefix = rMap.GetKeyByAttrName( sAttrName,&sLocalName );
        const rtl::OUString sValue = _xAttrList->getValueByIndex( i );

        switch( rTokenMap.Get( nPrefix, sLocalName ) )
        {
            case XML_TOK_MASTER:
                sMasterField = sValue;
                break;
            case XML_TOK_SUB_DETAIL:
                sDetailField = sValue;
                break;
            default:
                break;
        }
    }
    if ( !sDetailField.getLength() )
        sDetailField = sMasterField;
    m_pReport->addMasterDetailPair(::std::pair< ::rtl::OUString,::rtl::OUString >(sMasterField,sDetailField));
}
// -----------------------------------------------------------------------------

OXMLMasterFields::~OXMLMasterFields()
{
    DBG_DTOR( rpt_OXMLMasterFields,NULL);
}

// -----------------------------------------------------------------------------
SvXMLImportContext* OXMLMasterFields::CreateChildContext(
        sal_uInt16 _nPrefix,
        const ::rtl::OUString& _rLocalName,
        const Reference< XAttributeList > & xAttrList )
{
    SvXMLImportContext *pContext = 0;
    const SvXMLTokenMap&    rTokenMap   = static_cast<ORptFilter&>(GetImport()).GetSubDocumentElemTokenMap();

    switch( rTokenMap.Get( _nPrefix, _rLocalName ) )
    {
        case XML_TOK_MASTER_DETAIL_FIELD:
            {
                GetImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
                pContext = new OXMLMasterFields(static_cast<ORptFilter&>(GetImport()), _nPrefix, _rLocalName,xAttrList ,m_pReport);
            }
            break;
        default:
            break;
    }

    if( !pContext )
        pContext = new SvXMLImportContext( GetImport(), _nPrefix, _rLocalName );

    return pContext;
}

//----------------------------------------------------------------------------
} // namespace rptxml
// -----------------------------------------------------------------------------
<commit_msg>INTEGRATION: CWS rptchart02 (1.5.4); FILE MERGED 2008/04/16 06:29:18 oj 1.5.4.2: RESYNC: (1.5-1.6); FILE MERGED 2008/03/12 09:45:17 oj 1.5.4.1: impl chart handling<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: xmlMasterFields.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#include "precompiled_reportdesign.hxx"
#include "xmlMasterFields.hxx"
#include "xmlfilter.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnmspe.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmlEnums.hxx"
#include "xmlReport.hxx"
#include <tools/debug.hxx>

namespace rptxml
{
    using namespace ::com::sun::star;
    using namespace ::com::sun::star::report;
    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::xml::sax;
DBG_NAME( rpt_OXMLMasterFields )

OXMLMasterFields::OXMLMasterFields( ORptFilter& rImport,
                sal_uInt16 nPrfx, const ::rtl::OUString& rLName,
                const Reference< XAttributeList > & _xAttrList
                ,IMasterDetailFieds* _pReport
                ) :
    SvXMLImportContext( rImport, nPrfx, rLName)
,m_pReport(_pReport)
{
    DBG_CTOR( rpt_OXMLMasterFields,NULL);

    const SvXMLNamespaceMap& rMap = rImport.GetNamespaceMap();
    const SvXMLTokenMap& rTokenMap = rImport.GetSubDocumentElemTokenMap();

    ::rtl::OUString sMasterField,sDetailField;
    const sal_Int16 nLength = (_xAttrList.is()) ? _xAttrList->getLength() : 0;
    for(sal_Int16 i = 0; i < nLength; ++i)
    {
        ::rtl::OUString sLocalName;
        const rtl::OUString sAttrName = _xAttrList->getNameByIndex( i );
        const sal_uInt16 nPrefix = rMap.GetKeyByAttrName( sAttrName,&sLocalName );
        const rtl::OUString sValue = _xAttrList->getValueByIndex( i );

        switch( rTokenMap.Get( nPrefix, sLocalName ) )
        {
            case XML_TOK_MASTER:
                sMasterField = sValue;
                break;
            case XML_TOK_SUB_DETAIL:
                sDetailField = sValue;
                break;
            default:
                break;
        }
    }
    if ( !sDetailField.getLength() )
        sDetailField = sMasterField;
    if ( sMasterField.getLength() )
        m_pReport->addMasterDetailPair(::std::pair< ::rtl::OUString,::rtl::OUString >(sMasterField,sDetailField));
}
// -----------------------------------------------------------------------------

OXMLMasterFields::~OXMLMasterFields()
{
    DBG_DTOR( rpt_OXMLMasterFields,NULL);
}

// -----------------------------------------------------------------------------
SvXMLImportContext* OXMLMasterFields::CreateChildContext(
        sal_uInt16 _nPrefix,
        const ::rtl::OUString& _rLocalName,
        const Reference< XAttributeList > & xAttrList )
{
    SvXMLImportContext *pContext = 0;
    const SvXMLTokenMap&    rTokenMap   = static_cast<ORptFilter&>(GetImport()).GetSubDocumentElemTokenMap();

    switch( rTokenMap.Get( _nPrefix, _rLocalName ) )
    {
        case XML_TOK_MASTER_DETAIL_FIELD:
            {
                GetImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
                pContext = new OXMLMasterFields(static_cast<ORptFilter&>(GetImport()), _nPrefix, _rLocalName,xAttrList ,m_pReport);
            }
            break;
        default:
            break;
    }

    if( !pContext )
        pContext = new SvXMLImportContext( GetImport(), _nPrefix, _rLocalName );

    return pContext;
}

//----------------------------------------------------------------------------
} // namespace rptxml
// -----------------------------------------------------------------------------
<|endoftext|>