<commit_before>#ifndef LIBTEN_HTTP_SERVER_HH
#define LIBTEN_HTTP_SERVER_HH

#include <fnmatch.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/compare.hpp>
#include <chrono>
#include <functional>
#include <netinet/tcp.h>

#include "ten/buffer.hh"
#include "ten/logging.hh"
#include "ten/net.hh"
#include "ten/http/http_message.hh"
#include "ten/uri.hh"

namespace ten {

//! http request/response pair; keeps reference to request and socket
// (the term "exchange" appears in the standard)

struct http_exchange {
    http_request &req;
    netsock &sock;
    http_response resp {404};
    bool resp_sent {false};
    std::chrono::high_resolution_clock::time_point start;

    http_exchange(http_request &req_, netsock &sock_)
        : req(req_),
          sock(sock_),
          start(std::chrono::steady_clock::now())
        {}

    http_exchange(const http_exchange &) = delete;
    http_exchange &operator=(const http_exchange &) = delete;

    ~http_exchange() {
        if (!resp_sent) {
            // ensure a response is sent
            send_response();
        }
        if (resp.close_after()) {
            sock.close();
        }
    }

    //! compose a uri from the request uri
    uri get_uri(optional<std::string> host = nullopt) const {
        if (!host) {
            if (boost::starts_with(req.uri, "http://")) {
                // TODO: transform to preserve passed in host
                return req.uri;
            }
            host = req.get(hs::Host);
            if (!host)
                host.emplace("localhost");
        }
        uri tmp;
        tmp.scheme = "http";
        tmp.host = *host;
        tmp.path = req.uri;
        return tmp.compose();
    }

    //! send response to this request
    ssize_t send_response() {
        if (resp_sent) return 0;
        resp_sent = true;
        // TODO: Content-Length might be good to add to normal responses,
        //    but only if Transfer-Encoding isn't chunked?
        if (resp.status_code >= 400 && resp.status_code <= 599
            && !resp.get(hs::Content_Length)
            && req.method != hs::HEAD)
        {
            resp.set(hs::Content_Length, resp.body.size());
        }

        // HTTP/1.1 requires Date, so lets add it
        if (!resp.get(hs::Date)) {
            resp.set(hs::Date, http_base::rfc822_date());
        }

        // obey client's wishes on closing if we have none of our own,
        //  else prefer to keep http 1.1 open
        if (!resp.get(hs::Connection)) {
            const auto conn_hdr = req.get(hs::Connection);
            if (conn_hdr)
                resp.set(hs::Connection, *conn_hdr);
            else if (req.version == http_1_0)
                resp.set(hs::Connection, hs::close);
        }

        auto data = resp.data();
        if (!resp.body.empty() && req.method != hs::HEAD) {
            data += resp.body;
        }
        ssize_t nw = sock.send(data.data(), data.size());
        return nw;
    }

    //! the ip of the host making the request
    //! might use the X-Forwarded-For header
    optional<std::string> agent_ip(bool use_xff=false) const {
        if (use_xff) {
            auto xff_hdr = req.get("X-Forwarded-For");
            if (xff_hdr && !(*xff_hdr).empty()) {
                const char *xff = xff_hdr->c_str();
                // pick the first addr
                int i;
                for (i=0; *xff && i<256 && !isdigit((unsigned char)*xff); i++, xff++) {}
                if (*xff && i < 256) {
                    // now, find the end
                    const char *e = xff;
                    for (i = 0; *e && i<256 && (isdigit((unsigned char)*e) || *e == '.'); i++, e++) {}
                    if (i < 256 && e >= xff + 7 ) {
                        return std::string(xff, e - xff);
                    }
                }
            }
        }
        address addr;
        if (sock.getpeername(addr)) {
            char buf[INET6_ADDRSTRLEN];
            if (addr.ntop(buf, sizeof(buf))) {
                return optional<std::string>(emplace, buf);
            }
        }
        return nullopt;
    }
};

//! basic http server
class http_server : public netsock_server {
public:
    typedef std::function<void (http_exchange &)> callback_type;

    std::function<void ()> connect_watch;
    std::function<void ()> disconnect_watch;

protected:
    struct route {
        std::string pattern;
        callback_type callback;
        int fnmatch_flags;

        route(const std::string &pattern_,
                const callback_type &callback_,
                int fnmatch_flags_=0)
            : pattern(pattern_), callback(callback_), fnmatch_flags(fnmatch_flags_) {}
    };

    std::vector<route> _routes;
    callback_type _log_func;

public:
    http_server(size_t stacksize_=default_stacksize, optional_timeout recv_timeout_ms_={})
        : netsock_server("http", stacksize_, recv_timeout_ms_)
    {
    }

    //! add a callback for a uri with an fnmatch pattern
    void add_route(const std::string &pattern,
            const callback_type &callback,
            int fnmatch_flags = 0)
    {
        _routes.emplace_back(pattern, callback, fnmatch_flags);
    }

    //! set logging function, called after every exchange
    void set_log_callback(const callback_type &f) {
        _log_func = f;
    }

private:

    void setup_listen_socket(netsock &s) override {
        netsock_server::setup_listen_socket(s);
        s.setsockopt(IPPROTO_TCP, TCP_DEFER_ACCEPT, 30);
    }

    void on_connection(netsock &s) override {
        // TODO: tuneable buffer sizes
        buffer buf(4*1024);
        http_parser parser;

        if (connect_watch) {
            connect_watch();
        }

        bool nodelay_set = false;
        http_request req;
        while (s.valid()) {
            req.parser_init(&parser);
            bool got_headers = false;
            for (;;) {
                buf.reserve(4*1024);
                ssize_t nr = -1;
                if (buf.size() == 0) {
                    nr = s.recv(buf.back(), buf.available(), 0, _recv_timeout_ms);
                    if (nr < 0) goto done;
                    buf.commit(nr);
                }
                size_t nparse = buf.size();
                req.parse(&parser, buf.front(), nparse);
                buf.remove(nparse);
                if (req.complete) {
                    DVLOG(4) << req.data();
                    // handle http exchange (request -> response)
                    http_exchange ex(req, s);
                    if (!nodelay_set && !req.close_after()) {
                        // this is likely a persistent connection, so low-latency sending is worth the overh
                        s.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1);
                        nodelay_set = true;
                    }
                    handle_exchange(ex);
                    break;
                }
                if (nr == 0) goto done;
                if (!got_headers && !req.method.empty()) {
                    got_headers = true;
                    auto exp_hdr = req.get("Expect");
                    if (exp_hdr && *exp_hdr == "100-continue") {
                        http_response cont_resp(100);
                        std::string data = cont_resp.data();
                        ssize_t nw = s.send(data.data(), data.size());
                        (void)nw;
                    }
                }
            }
        }
done:
        if (disconnect_watch) {
            disconnect_watch();
        }
    }

    void handle_exchange(http_exchange &ex) {
        const auto path = ex.req.path();
        DVLOG(5) << "path: " << path;
        // not super efficient, but good enough
        // note: empty string pattern matches everything
        for (const auto &i : _routes) {
            DVLOG(5) << "matching pattern: " << i.pattern;
            if (i.pattern.empty() || fnmatch(i.pattern.c_str(), path.c_str(), i.fnmatch_flags) == 0) {
                try {
                    i.callback(std::ref(ex));
                } catch (std::exception &e) {
                    DVLOG(2) << "unhandled exception in route [" << i.pattern << "]: " << e.what();
                    ex.resp = http_response(500, http_headers{hs::Connection, hs::close});
                    std::string msg = e.what();
                    if (!msg.empty() && *msg.rbegin() != '\n')
                        msg += '\n';
                    ex.resp.set_body(msg, hs::text_plain);
                    ex.send_response();
                }
                break;
            }
        }
        if (_log_func) {
            _log_func(ex);
        }
    }
};

} // end namespace ten

#endif // LIBTEN_HTTP_SERVER_HH
<commit_msg>immediately stop http parsing on socket eof<commit_after>#ifndef LIBTEN_HTTP_SERVER_HH
#define LIBTEN_HTTP_SERVER_HH

#include <fnmatch.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/compare.hpp>
#include <chrono>
#include <functional>
#include <netinet/tcp.h>

#include "ten/buffer.hh"
#include "ten/logging.hh"
#include "ten/net.hh"
#include "ten/http/http_message.hh"
#include "ten/uri.hh"

namespace ten {

//! http request/response pair; keeps reference to request and socket
// (the term "exchange" appears in the standard)

struct http_exchange {
    http_request &req;
    netsock &sock;
    http_response resp {404};
    bool resp_sent {false};
    std::chrono::high_resolution_clock::time_point start;

    http_exchange(http_request &req_, netsock &sock_)
        : req(req_),
          sock(sock_),
          start(std::chrono::steady_clock::now())
        {}

    http_exchange(const http_exchange &) = delete;
    http_exchange &operator=(const http_exchange &) = delete;

    ~http_exchange() {
        if (!resp_sent) {
            // ensure a response is sent
            send_response();
        }
        if (resp.close_after()) {
            sock.close();
        }
    }

    //! compose a uri from the request uri
    uri get_uri(optional<std::string> host = nullopt) const {
        if (!host) {
            if (boost::starts_with(req.uri, "http://")) {
                // TODO: transform to preserve passed in host
                return req.uri;
            }
            host = req.get(hs::Host);
            if (!host)
                host.emplace("localhost");
        }
        uri tmp;
        tmp.scheme = "http";
        tmp.host = *host;
        tmp.path = req.uri;
        return tmp.compose();
    }

    //! send response to this request
    ssize_t send_response() {
        if (resp_sent) return 0;
        resp_sent = true;
        // TODO: Content-Length might be good to add to normal responses,
        //    but only if Transfer-Encoding isn't chunked?
        if (resp.status_code >= 400 && resp.status_code <= 599
            && !resp.get(hs::Content_Length)
            && req.method != hs::HEAD)
        {
            resp.set(hs::Content_Length, resp.body.size());
        }

        // HTTP/1.1 requires Date, so lets add it
        if (!resp.get(hs::Date)) {
            resp.set(hs::Date, http_base::rfc822_date());
        }

        // obey client's wishes on closing if we have none of our own,
        //  else prefer to keep http 1.1 open
        if (!resp.get(hs::Connection)) {
            const auto conn_hdr = req.get(hs::Connection);
            if (conn_hdr)
                resp.set(hs::Connection, *conn_hdr);
            else if (req.version == http_1_0)
                resp.set(hs::Connection, hs::close);
        }

        auto data = resp.data();
        if (!resp.body.empty() && req.method != hs::HEAD) {
            data += resp.body;
        }
        ssize_t nw = sock.send(data.data(), data.size());
        return nw;
    }

    //! the ip of the host making the request
    //! might use the X-Forwarded-For header
    optional<std::string> agent_ip(bool use_xff=false) const {
        if (use_xff) {
            auto xff_hdr = req.get("X-Forwarded-For");
            if (xff_hdr && !(*xff_hdr).empty()) {
                const char *xff = xff_hdr->c_str();
                // pick the first addr
                int i;
                for (i=0; *xff && i<256 && !isdigit((unsigned char)*xff); i++, xff++) {}
                if (*xff && i < 256) {
                    // now, find the end
                    const char *e = xff;
                    for (i = 0; *e && i<256 && (isdigit((unsigned char)*e) || *e == '.'); i++, e++) {}
                    if (i < 256 && e >= xff + 7 ) {
                        return std::string(xff, e - xff);
                    }
                }
            }
        }
        address addr;
        if (sock.getpeername(addr)) {
            char buf[INET6_ADDRSTRLEN];
            if (addr.ntop(buf, sizeof(buf))) {
                return optional<std::string>(emplace, buf);
            }
        }
        return nullopt;
    }
};

//! basic http server
class http_server : public netsock_server {
public:
    typedef std::function<void (http_exchange &)> callback_type;

    std::function<void ()> connect_watch;
    std::function<void ()> disconnect_watch;

protected:
    struct route {
        std::string pattern;
        callback_type callback;
        int fnmatch_flags;

        route(const std::string &pattern_,
                const callback_type &callback_,
                int fnmatch_flags_=0)
            : pattern(pattern_), callback(callback_), fnmatch_flags(fnmatch_flags_) {}
    };

    std::vector<route> _routes;
    callback_type _log_func;

public:
    http_server(size_t stacksize_=default_stacksize, optional_timeout recv_timeout_ms_={})
        : netsock_server("http", stacksize_, recv_timeout_ms_)
    {
    }

    //! add a callback for a uri with an fnmatch pattern
    void add_route(const std::string &pattern,
            const callback_type &callback,
            int fnmatch_flags = 0)
    {
        _routes.emplace_back(pattern, callback, fnmatch_flags);
    }

    //! set logging function, called after every exchange
    void set_log_callback(const callback_type &f) {
        _log_func = f;
    }

private:

    void setup_listen_socket(netsock &s) override {
        netsock_server::setup_listen_socket(s);
        s.setsockopt(IPPROTO_TCP, TCP_DEFER_ACCEPT, 30);
    }

    void on_connection(netsock &s) override {
        // TODO: tuneable buffer sizes
        buffer buf(4*1024);
        http_parser parser;

        if (connect_watch) {
            connect_watch();
        }

        bool nodelay_set = false;
        http_request req;
        while (s.valid()) {
            req.parser_init(&parser);
            bool got_headers = false;
            for (;;) {
                buf.reserve(4*1024);
                ssize_t nr = -1;
                if (buf.size() == 0) {
                    nr = s.recv(buf.back(), buf.available(), 0, _recv_timeout_ms);
                    if (nr <= 0) goto done;
                    buf.commit(nr);
                }
                size_t nparse = buf.size();
                req.parse(&parser, buf.front(), nparse);
                buf.remove(nparse);
                if (req.complete) {
                    DVLOG(4) << req.data();
                    // handle http exchange (request -> response)
                    http_exchange ex(req, s);
                    if (!nodelay_set && !req.close_after()) {
                        // this is likely a persistent connection, so low-latency sending is worth the overh
                        s.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1);
                        nodelay_set = true;
                    }
                    handle_exchange(ex);
                    break;
                }
                if (nr == 0) goto done;
                if (!got_headers && !req.method.empty()) {
                    got_headers = true;
                    auto exp_hdr = req.get("Expect");
                    if (exp_hdr && *exp_hdr == "100-continue") {
                        http_response cont_resp(100);
                        std::string data = cont_resp.data();
                        ssize_t nw = s.send(data.data(), data.size());
                        (void)nw;
                    }
                }
            }
        }
done:
        if (disconnect_watch) {
            disconnect_watch();
        }
    }

    void handle_exchange(http_exchange &ex) {
        const auto path = ex.req.path();
        DVLOG(5) << "path: " << path;
        // not super efficient, but good enough
        // note: empty string pattern matches everything
        for (const auto &i : _routes) {
            DVLOG(5) << "matching pattern: " << i.pattern;
            if (i.pattern.empty() || fnmatch(i.pattern.c_str(), path.c_str(), i.fnmatch_flags) == 0) {
                try {
                    i.callback(std::ref(ex));
                } catch (std::exception &e) {
                    DVLOG(2) << "unhandled exception in route [" << i.pattern << "]: " << e.what();
                    ex.resp = http_response(500, http_headers{hs::Connection, hs::close});
                    std::string msg = e.what();
                    if (!msg.empty() && *msg.rbegin() != '\n')
                        msg += '\n';
                    ex.resp.set_body(msg, hs::text_plain);
                    ex.send_response();
                }
                break;
            }
        }
        if (_log_func) {
            _log_func(ex);
        }
    }
};

} // end namespace ten

#endif // LIBTEN_HTTP_SERVER_HH
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $$
  Language:  C++
  Date:      $$
  Version:   $$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
// .NAME vtkExtractEdges - extract cell edges from any type of data
// .SECTION Description
// vtkExtractEdges is a filter to extract edges from a dataset. Edges
// are extracted as lines or polylines.
// .SECTION See Also
// vtkFeatureEdges

#ifndef __vtkExtractEdges_h
#define __vtkExtractEdges_h

#include "vtkDataSetToPolyFilter.hh"

class vtkExtractEdges : public vtkDataSetToPolyFilter
{
public:
  vtkExtractEdges();
  char *GetClassName() {return "vtkExtractEdges";};
  void PrintSelf(ostream& os, vtkIndent indent);

protected:
  // Usual data generation method
  void Execute();

};

#endif

<commit_msg>ENH: Fixed header<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkExtractEdges.hh
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
// .NAME vtkExtractEdges - extract cell edges from any type of data
// .SECTION Description
// vtkExtractEdges is a filter to extract edges from a dataset. Edges
// are extracted as lines or polylines.
// .SECTION See Also
// vtkFeatureEdges

#ifndef __vtkExtractEdges_h
#define __vtkExtractEdges_h

#include "vtkDataSetToPolyFilter.hh"

class vtkExtractEdges : public vtkDataSetToPolyFilter
{
public:
  vtkExtractEdges();
  char *GetClassName() {return "vtkExtractEdges";};
  void PrintSelf(ostream& os, vtkIndent indent);

protected:
  // Usual data generation method
  void Execute();

};

#endif

<|endoftext|>


<commit_before>/**
 * @file lltrans.cpp
 * @brief LLTrans implementation
 *
 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "lltrans.h"

#include "llfasttimer.h"	// for call count statistics
#include "llxuiparser.h"

#include <map>

LLTrans::template_map_t LLTrans::sStringTemplates;
LLStringUtil::format_map_t LLTrans::sDefaultArgs;

struct StringDef : public LLInitParam::Block<StringDef>
{
	Mandatory<std::string> name;
	Mandatory<std::string> value;

	StringDef()
	:	name("name"),
		value("value")
	{}
};

struct StringTable : public LLInitParam::Block<StringTable>
{
	Multiple<StringDef> strings;
	StringTable()
	:	strings("string")
	{}
};

//static
bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set<std::string>& default_args)
{
	std::string xml_filename = "(strings file)";
	if (!root->hasName("strings"))
	{
		llerrs << "Invalid root node name in " << xml_filename
			<< ": was " << root->getName() << ", expected \"strings\"" << llendl;
	}

	StringTable string_table;
	LLXUIParser parser;
	parser.readXUI(root, string_table, xml_filename);

	if (!string_table.validateBlock())
	{
		llerrs << "Problem reading strings: " << xml_filename << llendl;
		return false;
	}

	sStringTemplates.clear();
	sDefaultArgs.clear();

	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin();
		it != string_table.strings.end();
		++it)
	{
		LLTransTemplate xml_template(it->name, it->value);
		sStringTemplates[xml_template.mName] = xml_template;

		std::set<std::string>::const_iterator iter = default_args.find(xml_template.mName);
		if (iter != default_args.end())
		{
			std::string name = *iter;
			if (name[0] != '[')
				name = llformat("[%s]",name.c_str());
			sDefaultArgs[name] = xml_template.mText;
		}
	}

	return true;
}

//static
bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root)
{
	std::string xml_filename = "(language strings file)";
	if (!root->hasName("strings"))
	{
		llerrs << "Invalid root node name in " << xml_filename
		<< ": was " << root->getName() << ", expected \"strings\"" << llendl;
	}

	StringTable string_table;
	LLXUIParser parser;
	parser.readXUI(root, string_table, xml_filename);

	if (!string_table.validateBlock())
	{
		llerrs << "Problem reading strings: " << xml_filename << llendl;
		return false;
	}

	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin();
		it != string_table.strings.end();
		++it)
	{
		// share the same map with parseStrings() so we can search the strings using the same getString() function.- angela
		LLTransTemplate xml_template(it->name, it->value);
		sStringTemplates[xml_template.mName] = xml_template;
	}

	return true;
}

static LLFastTimer::DeclareTimer FTM_GET_TRANS("Translate string");

//static
std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args)
{
	// Don't care about time as much as call count.  Make sure we're not
	// calling LLTrans::getString() in an inner loop. JC
	LLFastTimer timer(FTM_GET_TRANS);

	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
	if (iter != sStringTemplates.end())
	{
		std::string text = iter->second.mText;
		LLStringUtil::format_map_t args = sDefaultArgs;
		args.insert(msg_args.begin(), msg_args.end());
		LLStringUtil::format(text, args);

		return text;
	}
	else
	{
		LLSD args;
		args["STRING_NAME"] = xml_desc;
		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;

		//LLNotificationsUtil::add("MissingString", args); // *TODO: resurrect
		//return xml_desc;

		return "MissingString("+xml_desc+")";
	}
}

//static
bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args)
{
	LLFastTimer timer(FTM_GET_TRANS);

	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
	if (iter != sStringTemplates.end())
	{
		std::string text = iter->second.mText;
		LLStringUtil::format_map_t args = sDefaultArgs;
		args.insert(msg_args.begin(), msg_args.end());
		LLStringUtil::format(text, args);
		result = text;
		return true;
	}
	else
	{
		LLSD args;
		args["STRING_NAME"] = xml_desc;
		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
		//LLNotificationsUtil::add("MissingString", args);

		return false;
	}
}

//static
std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count)
{
	// Compute which string identifier to use
	const char* form = "";
	if (language == "ru") // Russian
	{
		// From GNU ngettext()
		// Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
		if (count % 10 == 1
			&& count % 100 != 11)
		{
			// singular, "1 item"
			form = "A";
		}
		else if (count % 10 >= 2
			&& count % 10 <= 4
			&& (count % 100 < 10 || count % 100 >= 20) )
		{
			// special case "2 items", "23 items", but not "13 items"
			form = "B";
		}
		else
		{
			// English-style plural, "5 items"
			form = "C";
		}
	}
	else if (language == "fr" || language == "pt") // French, Brazilian Portuguese
	{
		// French and Portuguese treat zero as a singular "0 item" not "0 items"
		if (count == 0 || count == 1)
		{
			form = "A";
		}
		else
		{
			// English-style plural
			form = "B";
		}
	}
	else // default
	{
		// languages like English with 2 forms, singular and plural
		if (count == 1)
		{
			// "1 item"
			form = "A";
		}
		else
		{
			// "2 items", also use plural for "0 items"
			form = "B";
		}
	}

	// Translate that string
	LLStringUtil::format_map_t args;
	args["[COUNT]"] = llformat("%d", count);

	// Look up "AgeYearsB" or "AgeWeeksC" including the "form"
	std::string key = llformat("%s%s", xml_desc.c_str(), form);
	return getString(key, args);
}

void LLTrans::setDefaultArg(const std::string& name, const std::string& value)
{
	sDefaultArgs[name] = value;
}<commit_msg>fix for linux build<commit_after>/**
 * @file lltrans.cpp
 * @brief LLTrans implementation
 *
 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "lltrans.h"

#include "llfasttimer.h"	// for call count statistics
#include "llxuiparser.h"

#include <map>

LLTrans::template_map_t LLTrans::sStringTemplates;
LLStringUtil::format_map_t LLTrans::sDefaultArgs;

struct StringDef : public LLInitParam::Block<StringDef>
{
	Mandatory<std::string> name;
	Mandatory<std::string> value;

	StringDef()
	:	name("name"),
		value("value")
	{}
};

struct StringTable : public LLInitParam::Block<StringTable>
{
	Multiple<StringDef> strings;
	StringTable()
	:	strings("string")
	{}
};

//static
bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set<std::string>& default_args)
{
	std::string xml_filename = "(strings file)";
	if (!root->hasName("strings"))
	{
		llerrs << "Invalid root node name in " << xml_filename
			<< ": was " << root->getName() << ", expected \"strings\"" << llendl;
	}

	StringTable string_table;
	LLXUIParser parser;
	parser.readXUI(root, string_table, xml_filename);

	if (!string_table.validateBlock())
	{
		llerrs << "Problem reading strings: " << xml_filename << llendl;
		return false;
	}

	sStringTemplates.clear();
	sDefaultArgs.clear();

	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin();
		it != string_table.strings.end();
		++it)
	{
		LLTransTemplate xml_template(it->name, it->value);
		sStringTemplates[xml_template.mName] = xml_template;

		std::set<std::string>::const_iterator iter = default_args.find(xml_template.mName);
		if (iter != default_args.end())
		{
			std::string name = *iter;
			if (name[0] != '[')
				name = llformat("[%s]",name.c_str());
			sDefaultArgs[name] = xml_template.mText;
		}
	}

	return true;
}

//static
bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root)
{
	std::string xml_filename = "(language strings file)";
	if (!root->hasName("strings"))
	{
		llerrs << "Invalid root node name in " << xml_filename
		<< ": was " << root->getName() << ", expected \"strings\"" << llendl;
	}

	StringTable string_table;
	LLXUIParser parser;
	parser.readXUI(root, string_table, xml_filename);

	if (!string_table.validateBlock())
	{
		llerrs << "Problem reading strings: " << xml_filename << llendl;
		return false;
	}

	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin();
		it != string_table.strings.end();
		++it)
	{
		// share the same map with parseStrings() so we can search the strings using the same getString() function.- angela
		LLTransTemplate xml_template(it->name, it->value);
		sStringTemplates[xml_template.mName] = xml_template;
	}

	return true;
}

static LLFastTimer::DeclareTimer FTM_GET_TRANS("Translate string");

//static
std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args)
{
	// Don't care about time as much as call count.  Make sure we're not
	// calling LLTrans::getString() in an inner loop. JC
	LLFastTimer timer(FTM_GET_TRANS);

	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
	if (iter != sStringTemplates.end())
	{
		std::string text = iter->second.mText;
		LLStringUtil::format_map_t args = sDefaultArgs;
		args.insert(msg_args.begin(), msg_args.end());
		LLStringUtil::format(text, args);

		return text;
	}
	else
	{
		LLSD args;
		args["STRING_NAME"] = xml_desc;
		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;

		//LLNotificationsUtil::add("MissingString", args); // *TODO: resurrect
		//return xml_desc;

		return "MissingString("+xml_desc+")";
	}
}

//static
bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args)
{
	LLFastTimer timer(FTM_GET_TRANS);

	template_map_t::iterator iter = sStringTemplates.find(xml_desc);
	if (iter != sStringTemplates.end())
	{
		std::string text = iter->second.mText;
		LLStringUtil::format_map_t args = sDefaultArgs;
		args.insert(msg_args.begin(), msg_args.end());
		LLStringUtil::format(text, args);
		result = text;
		return true;
	}
	else
	{
		LLSD args;
		args["STRING_NAME"] = xml_desc;
		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
		//LLNotificationsUtil::add("MissingString", args);

		return false;
	}
}

//static
std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count)
{
	// Compute which string identifier to use
	const char* form = "";
	if (language == "ru") // Russian
	{
		// From GNU ngettext()
		// Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
		if (count % 10 == 1
			&& count % 100 != 11)
		{
			// singular, "1 item"
			form = "A";
		}
		else if (count % 10 >= 2
			&& count % 10 <= 4
			&& (count % 100 < 10 || count % 100 >= 20) )
		{
			// special case "2 items", "23 items", but not "13 items"
			form = "B";
		}
		else
		{
			// English-style plural, "5 items"
			form = "C";
		}
	}
	else if (language == "fr" || language == "pt") // French, Brazilian Portuguese
	{
		// French and Portuguese treat zero as a singular "0 item" not "0 items"
		if (count == 0 || count == 1)
		{
			form = "A";
		}
		else
		{
			// English-style plural
			form = "B";
		}
	}
	else // default
	{
		// languages like English with 2 forms, singular and plural
		if (count == 1)
		{
			// "1 item"
			form = "A";
		}
		else
		{
			// "2 items", also use plural for "0 items"
			form = "B";
		}
	}

	// Translate that string
	LLStringUtil::format_map_t args;
	args["[COUNT]"] = llformat("%d", count);

	// Look up "AgeYearsB" or "AgeWeeksC" including the "form"
	std::string key = llformat("%s%s", xml_desc.c_str(), form);
	return getString(key, args);
}

void LLTrans::setDefaultArg(const std::string& name, const std::string& value)
{
	sDefaultArgs[name] = value;
}
<|endoftext|>


<commit_before>#include "BoundingBox.hpp"
#include "QuadKey.hpp"
#include "entities/Element.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "index/ElementStore.hpp"
#include "index/ElementGeometryClipper.hpp"

using namespace utymap;
using namespace utymap::entities;

using namespace utymap::mapcss;

namespace {
/// Max precision for Lat/Lon
const double Scale = 1E7;

using PointLocation = utymap::index::ElementGeometryClipper::PointLocation;

template<typename T, typename std::enable_if<std::is_same<T, Way>::value, std::size_t>::type = 0>
bool areConnected(const BoundingBox &, const BoundingBox &, bool allOutside) {
  return !allOutside;
}

template<typename T, typename std::enable_if<std::is_same<T, Area>::value, std::size_t>::type = 0>
bool areConnected(const BoundingBox &quadKeyBbox, const BoundingBox &elementBbox, bool allOutside) {
  return quadKeyBbox.intersects(elementBbox);
}

template<typename T>
PointLocation checkElement(const BoundingBox &quadKeyBbox, const T &element, ClipperLib::Path &elementShape) {
  elementShape.reserve(element.coordinates.size());
  bool allInside = true;
  bool allOutside = true;
  BoundingBox elementBbox;
  for (const GeoCoordinate &coord : element.coordinates) {
    bool contains = quadKeyBbox.contains(coord);
    allInside &= contains;
    allOutside &= !contains;
    elementBbox.expand(coord);

    auto x = static_cast<ClipperLib::cInt>(coord.longitude*Scale);
    auto y = static_cast<ClipperLib::cInt>(coord.latitude*Scale);
    elementShape.push_back(ClipperLib::IntPoint(x, y));
  }

  return allInside ? PointLocation::AllInside :
         (areConnected<T>(quadKeyBbox, elementBbox, allOutside) ? PointLocation::Mixed : PointLocation::AllOutside);
}

template<typename T>
void setCoordinates(T &t, const ClipperLib::Path &path) {
  t.coordinates.reserve(path.size());
  for (const auto &c : path) {
    t.coordinates.push_back(GeoCoordinate(c.Y/Scale, c.X/Scale));
  }
}

ClipperLib::Path createPathFromBoundingBox(const BoundingBox &quadKeyBbox) {
  double xMin = quadKeyBbox.minPoint.longitude, yMin = quadKeyBbox.minPoint.latitude,
      xMax = quadKeyBbox.maxPoint.longitude, yMax = quadKeyBbox.maxPoint.latitude;
  ClipperLib::Path rect;
  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                      static_cast<ClipperLib::cInt>(yMin*Scale)));

  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                      static_cast<ClipperLib::cInt>(yMin*Scale)));

  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                      static_cast<ClipperLib::cInt>(yMax*Scale)));

  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                      static_cast<ClipperLib::cInt>(yMax*Scale)));
  return std::move(rect);
}

template<typename T>
std::shared_ptr<Element> clipElement(ClipperLib::ClipperEx &clipper,
                                     const BoundingBox &bbox,
                                     const T &element,
                                     bool isClosed) {
  ClipperLib::Path elementShape;
  PointLocation pointLocation = checkElement(bbox, element, elementShape);
  // 1. all geometry inside current quadkey: no need to truncate.
  if (pointLocation==PointLocation::AllInside) {
    return std::make_shared<T>(element);
  }

  // 2. all geometry outside : way should be skipped
  if (pointLocation==PointLocation::AllOutside) {
    return nullptr;
  }

  ClipperLib::PolyTree solution;
  clipper.AddPath(elementShape, ClipperLib::ptSubject, isClosed);
  clipper.Execute(ClipperLib::ctIntersection, solution);
  clipper.removeSubject();

  std::size_t count = static_cast<std::size_t>(solution.Total());

  // 3. way intersects border only once: store a copy with clipped geometry
  if (count==1) {
    auto clippedElement = std::make_shared<T>();
    clippedElement->id = element.id;
    clippedElement->tags = element.tags;
    setCoordinates(*clippedElement, solution.GetFirst()->Contour);

    return clippedElement;
  }
  // 4. in this case, result should be stored as relation (collection of ways)
  if (count > 1) {
    auto relation = std::make_shared<Relation>();
    relation->id = element.id;
    relation->elements.reserve(count);
    ClipperLib::PolyNode *polyNode = solution.GetFirst();
    while (polyNode) {
      auto clippedElement = std::make_shared<T>();
      clippedElement->id = 0;
      clippedElement->tags = element.tags;
      setCoordinates(*clippedElement, polyNode->Contour);
      relation->elements.push_back(clippedElement);
      polyNode = polyNode->GetNext();
    }
    return relation;
  }

  // no intersection
  return nullptr;
}

std::shared_ptr<Element> clipWay(ClipperLib::ClipperEx &clipper, const BoundingBox &bbox, const Way &way) {
  return clipElement(clipper, bbox, way, false);
}

std::shared_ptr<Element> clipArea(ClipperLib::ClipperEx &clipper, const BoundingBox &bbox, const Area &area) {
  return clipElement(clipper, bbox, area, true);
}

std::shared_ptr<Element> clipRelation(ClipperLib::ClipperEx &clipper,
                                      const BoundingBox &bbox,
                                      const Relation &relation);

/// Visits relation and collects clipped elements
struct RelationVisitor : public ElementVisitor {
  RelationVisitor(ClipperLib::ClipperEx &clipper, const BoundingBox &quadKeyBbox) :
      relation(nullptr), clipper_(clipper), bbox_(quadKeyBbox) {
  }

  void visitNode(const Node &node) override {
    if (bbox_.contains(node.coordinate)) {
      ensureRelation();
      relation->elements.push_back(std::make_shared<Node>(node));
    }
  }

  void visitWay(const Way &way) override {
    addElement(clipWay(clipper_, bbox_, way));
  }

  void visitArea(const Area &area) override {
    addElement(clipArea(clipper_, bbox_, area));
  }

  void visitRelation(const Relation &relation) override {
    addElement(clipRelation(clipper_, bbox_, relation));
  }

  std::shared_ptr<Relation> relation;

 private:

  void ensureRelation() {
    if (relation==nullptr)
      relation = std::make_shared<Relation>();
  }

  void addElement(std::shared_ptr<Element> element) {
    if (element==nullptr) return;

    ensureRelation();

    relation->elements.push_back(element);
  }

  ClipperLib::ClipperEx &clipper_;
  const BoundingBox &bbox_;
};

std::shared_ptr<Element> clipRelation(ClipperLib::ClipperEx &clipper,
                                      const BoundingBox &bbox,
                                      const Relation &relation) {
  RelationVisitor visitor(clipper, bbox);

  for (const auto &element : relation.elements)
    element->accept(visitor);

  if (visitor.relation==nullptr)
    return nullptr;

  std::shared_ptr<Element> element = visitor.relation->elements.size()==1
    ? visitor.relation->elements.at(0)
    : visitor.relation;

  element->id = relation.id;

  return element;
}
}

namespace utymap {
namespace index {

ElementGeometryClipper::ElementGeometryClipper(Callback callback) :
    callback_(callback), quadKey_(), quadKeyBbox_(), clipper_() {
}

void ElementGeometryClipper::clipAndCall(const Element &element,
                                         const QuadKey &quadKey,
                                         const BoundingBox &quadKeyBbox) {
  quadKey_ = quadKey;
  quadKeyBbox_ = quadKeyBbox;
  clipper_.Clear();
  clipper_.AddPath(createPathFromBoundingBox(quadKeyBbox_), ClipperLib::ptClip, true);
  element.accept(*this);
}

void ElementGeometryClipper::visitNode(const Node &node) {
  if (quadKeyBbox_.contains(node.coordinate))
    callback_(node, quadKey_);
}

void ElementGeometryClipper::visitWay(const Way &way) {
  auto element = clipWay(clipper_, quadKeyBbox_, way);
  if (element!=nullptr)
    callback_(*element, quadKey_);
}

void ElementGeometryClipper::visitArea(const Area &area) {
  auto element = clipArea(clipper_, quadKeyBbox_, area);
  if (element!=nullptr)
    callback_(*element, quadKey_);
}

void ElementGeometryClipper::visitRelation(const Relation &relation) {
  auto element = clipRelation(clipper_, quadKeyBbox_, relation);
  if (element!=nullptr)
    callback_(*element, quadKey_);
}

}
}
<commit_msg>core: do not lose tags from relation itself while cllipping<commit_after>#include "BoundingBox.hpp"
#include "QuadKey.hpp"
#include "entities/Element.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "index/ElementStore.hpp"
#include "index/ElementGeometryClipper.hpp"

using namespace utymap;
using namespace utymap::entities;

using namespace utymap::mapcss;

namespace {
/// Max precision for Lat/Lon
const double Scale = 1E7;

using PointLocation = utymap::index::ElementGeometryClipper::PointLocation;

template<typename T, typename std::enable_if<std::is_same<T, Way>::value, std::size_t>::type = 0>
bool areConnected(const BoundingBox &, const BoundingBox &, bool allOutside) {
  return !allOutside;
}

template<typename T, typename std::enable_if<std::is_same<T, Area>::value, std::size_t>::type = 0>
bool areConnected(const BoundingBox &quadKeyBbox, const BoundingBox &elementBbox, bool allOutside) {
  return quadKeyBbox.intersects(elementBbox);
}

template<typename T>
PointLocation checkElement(const BoundingBox &quadKeyBbox, const T &element, ClipperLib::Path &elementShape) {
  elementShape.reserve(element.coordinates.size());
  bool allInside = true;
  bool allOutside = true;
  BoundingBox elementBbox;
  for (const GeoCoordinate &coord : element.coordinates) {
    bool contains = quadKeyBbox.contains(coord);
    allInside &= contains;
    allOutside &= !contains;
    elementBbox.expand(coord);

    auto x = static_cast<ClipperLib::cInt>(coord.longitude*Scale);
    auto y = static_cast<ClipperLib::cInt>(coord.latitude*Scale);
    elementShape.push_back(ClipperLib::IntPoint(x, y));
  }

  return allInside ? PointLocation::AllInside :
         (areConnected<T>(quadKeyBbox, elementBbox, allOutside) ? PointLocation::Mixed : PointLocation::AllOutside);
}

template<typename T>
void setCoordinates(T &t, const ClipperLib::Path &path) {
  t.coordinates.reserve(path.size());
  for (const auto &c : path) {
    t.coordinates.push_back(GeoCoordinate(c.Y/Scale, c.X/Scale));
  }
}

ClipperLib::Path createPathFromBoundingBox(const BoundingBox &quadKeyBbox) {
  double xMin = quadKeyBbox.minPoint.longitude, yMin = quadKeyBbox.minPoint.latitude,
      xMax = quadKeyBbox.maxPoint.longitude, yMax = quadKeyBbox.maxPoint.latitude;
  ClipperLib::Path rect;
  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                      static_cast<ClipperLib::cInt>(yMin*Scale)));

  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                      static_cast<ClipperLib::cInt>(yMin*Scale)));

  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                      static_cast<ClipperLib::cInt>(yMax*Scale)));

  rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                      static_cast<ClipperLib::cInt>(yMax*Scale)));
  return std::move(rect);
}

template<typename T>
std::shared_ptr<Element> clipElement(ClipperLib::ClipperEx &clipper,
                                     const BoundingBox &bbox,
                                     const T &element,
                                     bool isClosed) {
  ClipperLib::Path elementShape;
  PointLocation pointLocation = checkElement(bbox, element, elementShape);
  // 1. all geometry inside current quadkey: no need to truncate.
  if (pointLocation==PointLocation::AllInside) {
    return std::make_shared<T>(element);
  }

  // 2. all geometry outside : way should be skipped
  if (pointLocation==PointLocation::AllOutside) {
    return nullptr;
  }

  ClipperLib::PolyTree solution;
  clipper.AddPath(elementShape, ClipperLib::ptSubject, isClosed);
  clipper.Execute(ClipperLib::ctIntersection, solution);
  clipper.removeSubject();

  std::size_t count = static_cast<std::size_t>(solution.Total());

  // 3. way intersects border only once: store a copy with clipped geometry
  if (count==1) {
    auto clippedElement = std::make_shared<T>();
    clippedElement->id = element.id;
    clippedElement->tags = element.tags;
    setCoordinates(*clippedElement, solution.GetFirst()->Contour);

    return clippedElement;
  }
  // 4. in this case, result should be stored as relation (collection of ways)
  if (count > 1) {
    auto relation = std::make_shared<Relation>();
    relation->id = element.id;
    relation->elements.reserve(count);
    ClipperLib::PolyNode *polyNode = solution.GetFirst();
    while (polyNode) {
      auto clippedElement = std::make_shared<T>();
      clippedElement->id = 0;
      clippedElement->tags = element.tags;
      setCoordinates(*clippedElement, polyNode->Contour);
      relation->elements.push_back(clippedElement);
      polyNode = polyNode->GetNext();
    }
    return relation;
  }

  // no intersection
  return nullptr;
}

std::shared_ptr<Element> clipWay(ClipperLib::ClipperEx &clipper, const BoundingBox &bbox, const Way &way) {
  return clipElement(clipper, bbox, way, false);
}

std::shared_ptr<Element> clipArea(ClipperLib::ClipperEx &clipper, const BoundingBox &bbox, const Area &area) {
  return clipElement(clipper, bbox, area, true);
}

std::shared_ptr<Element> clipRelation(ClipperLib::ClipperEx &clipper,
                                      const BoundingBox &bbox,
                                      const Relation &relation);

/// Visits relation and collects clipped elements
struct RelationVisitor : public ElementVisitor {
  RelationVisitor(ClipperLib::ClipperEx &clipper, const BoundingBox &quadKeyBbox) :
      relation(nullptr), clipper_(clipper), bbox_(quadKeyBbox) {
  }

  void visitNode(const Node &node) override {
    if (bbox_.contains(node.coordinate)) {
      ensureRelation();
      relation->elements.push_back(std::make_shared<Node>(node));
    }
  }

  void visitWay(const Way &way) override {
    addElement(clipWay(clipper_, bbox_, way));
  }

  void visitArea(const Area &area) override {
    addElement(clipArea(clipper_, bbox_, area));
  }

  void visitRelation(const Relation &relation) override {
    addElement(clipRelation(clipper_, bbox_, relation));
  }

  std::shared_ptr<Relation> relation;

 private:

  void ensureRelation() {
    if (relation==nullptr)
      relation = std::make_shared<Relation>();
  }

  void addElement(std::shared_ptr<Element> element) {
    if (element==nullptr) return;

    ensureRelation();

    relation->elements.push_back(element);
  }

  ClipperLib::ClipperEx &clipper_;
  const BoundingBox &bbox_;
};

std::shared_ptr<Element> clipRelation(ClipperLib::ClipperEx &clipper,
                                      const BoundingBox &bbox,
                                      const Relation &relation) {
  RelationVisitor visitor(clipper, bbox);

  for (const auto &element : relation.elements)
    element->accept(visitor);

  if (visitor.relation==nullptr)
    return nullptr;

  std::shared_ptr<Element> element = visitor.relation->elements.size()==1
    ? visitor.relation->elements.at(0)
    : visitor.relation;

  element->id = relation.id;
  element->tags = relation.tags;

  return element;
}
}

namespace utymap {
namespace index {

ElementGeometryClipper::ElementGeometryClipper(Callback callback) :
    callback_(callback), quadKey_(), quadKeyBbox_(), clipper_() {
}

void ElementGeometryClipper::clipAndCall(const Element &element,
                                         const QuadKey &quadKey,
                                         const BoundingBox &quadKeyBbox) {
  quadKey_ = quadKey;
  quadKeyBbox_ = quadKeyBbox;
  clipper_.Clear();
  clipper_.AddPath(createPathFromBoundingBox(quadKeyBbox_), ClipperLib::ptClip, true);
  element.accept(*this);
}

void ElementGeometryClipper::visitNode(const Node &node) {
  if (quadKeyBbox_.contains(node.coordinate))
    callback_(node, quadKey_);
}

void ElementGeometryClipper::visitWay(const Way &way) {
  auto element = clipWay(clipper_, quadKeyBbox_, way);
  if (element!=nullptr)
    callback_(*element, quadKey_);
}

void ElementGeometryClipper::visitArea(const Area &area) {
  auto element = clipArea(clipper_, quadKeyBbox_, area);
  if (element!=nullptr)
    callback_(*element, quadKey_);
}

void ElementGeometryClipper::visitRelation(const Relation &relation) {
  auto element = clipRelation(clipper_, quadKeyBbox_, relation);
  if (element!=nullptr)
    callback_(*element, quadKey_);
}

}
}
<|endoftext|>


<commit_before>// @(#)root/tmva $Id$
// Author: Matt Jachowski

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Class  : TNeuron                                                               *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation (see header for description)                               *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Matt Jachowski  <jachowski@stanford.edu> - Stanford University, USA       *
 *                                                                                *
 * Copyright (c) 2005:                                                            *
 *      CERN, Switzerland                                                         *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

//_______________________________________________________________________
//
// Neuron class used by TMVA artificial neural network methods
//
//_______________________________________________________________________

#include "TH1D.h"

#ifndef ROOT_TMVA_MsgLogger
#include "TMVA/MsgLogger.h"
#endif
#ifndef ROOT_TMVA_TNeuron
#include "TMVA/TNeuron.h"
#endif
#ifndef ROOT_TMVA_TActivation
#include "TMVA/TActivation.h"
#endif
#ifndef ROOT_TMVA_Tools
#include "TMVA/Tools.h"
#endif
#ifndef ROOT_TMVA_TNeuronInput
#include "TMVA/TNeuronInput.h"
#endif

static const Int_t UNINITIALIZED = -1;

using std::vector;

ClassImp(TMVA::TNeuron)

TMVA::MsgLogger* TMVA::TNeuron::fgLogger = 0;

//______________________________________________________________________________
TMVA::TNeuron::TNeuron()
{
   // standard constructor
   if (!fgLogger) fgLogger = new MsgLogger("TNeuron",kDEBUG);
   InitNeuron();
}

TMVA::TNeuron::~TNeuron()
{
   // destructor
   if (fLinksIn != NULL)  delete fLinksIn;
   if (fLinksOut != NULL) delete fLinksOut;
}

void TMVA::TNeuron::InitNeuron()
{
   // initialize the neuron, most variables still need to be set via setters
   fLinksIn = new TObjArray();
   fLinksOut = new TObjArray();
   fValue = UNINITIALIZED;
   fActivationValue = UNINITIALIZED;
   fDelta = UNINITIALIZED;
   fDEDw = UNINITIALIZED;
   fError = UNINITIALIZED;
   fActivation = NULL;
   fForcedValue = kFALSE;
   fInputCalculator = NULL;
}

//______________________________________________________________________________
void TMVA::TNeuron::ForceValue(Double_t value)
{
   // force the value, typically for input and bias neurons
   fValue = value;
   fForcedValue = kTRUE;
}

//______________________________________________________________________________
void TMVA::TNeuron::CalculateValue()
{
   // calculate neuron input
   if (fForcedValue) return;
   fValue = fInputCalculator->GetInput(this);
}

//______________________________________________________________________________
void TMVA::TNeuron::CalculateActivationValue()
{
   // calculate neuron activation/output

   if (fActivation == NULL) {
      PrintMessage( kWARNING ,"No activation equation specified." );
      fActivationValue = UNINITIALIZED;
      return;
   }
   fActivationValue = fActivation->Eval(fValue);
}

//______________________________________________________________________________
void TMVA::TNeuron::CalculateDelta()
{
   // calculate error field

   // no need to adjust input neurons
   if (IsInputNeuron()) {
      fDelta = 0.0;
      return;
   }

   Double_t error;

   // output neuron should have error set all ready
   if (IsOutputNeuron()) error = fError;

   // need to calculate error for any other neuron
   else {
      error = 0.0;
      TSynapse* synapse = NULL;
      TObjArrayIter* iter = (TObjArrayIter*)fLinksOut->MakeIterator();

      while (true) {
         synapse = (TSynapse*) iter->Next();
         if (synapse == NULL) break;
         error += synapse->GetWeightedDelta();
      }

      delete iter;
   }

   fDelta = error * fActivation->EvalDerivative(GetValue());
}

//______________________________________________________________________________
void TMVA::TNeuron::SetInputCalculator(TNeuronInput* calculator)
{
   // set input calculator
   if (fInputCalculator != NULL) delete fInputCalculator;
   fInputCalculator = calculator;
}

//______________________________________________________________________________
void TMVA::TNeuron::SetActivationEqn(TActivation* activation)
{
   // set activation equation
   if (fActivation != NULL) delete fActivation;
   fActivation = activation;
}

//______________________________________________________________________________
void TMVA::TNeuron::AddPreLink(TSynapse* pre)
{
   // add synapse as a pre-link to this neuron
   if (IsInputNeuron()) return;
   fLinksIn->Add(pre);
}

//______________________________________________________________________________
void TMVA::TNeuron::AddPostLink(TSynapse* post)
{
   // add synapse as a post-link to this neuron
   if (IsOutputNeuron()) return;
   fLinksOut->Add(post);
}

//______________________________________________________________________________
void TMVA::TNeuron::DeletePreLinks()
{
   // delete all pre-links
   DeleteLinksArray(fLinksIn);
}

//______________________________________________________________________________
void TMVA::TNeuron::DeleteLinksArray(TObjArray*& links)
{
   // delete an array of TSynapses

   if (links == NULL) return;

   TSynapse* synapse = NULL;
   Int_t numLinks = links->GetEntriesFast();
   for (Int_t i=0; i<numLinks; i++) {
      synapse = (TSynapse*)links->At(i);
      if (synapse != NULL) delete synapse;
   }
   delete links;
   links = NULL;
}

//______________________________________________________________________________
void TMVA::TNeuron::SetError(Double_t error)
{
   // set error, this should only be done for an output neuron
   if (!IsOutputNeuron())
      PrintMessage( kWARNING, "Warning! Setting an error on a non-output neuron is probably not what you want to do." );

   fError = error;
}

//______________________________________________________________________________
void TMVA::TNeuron::UpdateSynapsesBatch()
{
   // update and adjust the pre-synapses for each neuron (input neuron has no pre-synapse)
   // this method should only be called in batch mode

   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->CalculateDelta();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::UpdateSynapsesSequential()
{
   // update the pre-synapses for each neuron (input neuron has no pre-synapse)
   // this method should only be called in sequential mode

   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->InitDelta();
      synapse->CalculateDelta();
      synapse->AdjustWeight();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::AdjustSynapseWeights()
{
   // adjust the pre-synapses' weights for each neuron (input neuron has no pre-synapse)
   // this method should only be called in batch mode

   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->AdjustWeight();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::InitSynapseDeltas()
{
   // initialize the error fields of all pre-neurons
   // this method should only be called in batch mode

   // an input neuron has no pre-weights to adjust
   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->InitDelta();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::PrintLinks(TObjArray* links) const
{
   // print an array of TSynapses, for debugging

   if (links == NULL) {
      Log() << kDEBUG << "\t\t\t<none>" << Endl;
      return;
   }

   TSynapse* synapse;

   Int_t numLinks = links->GetEntriesFast();
   for  (Int_t i = 0; i < numLinks; i++) {
      synapse = (TSynapse*)links->At(i);
      Log() << kDEBUG <<
         "\t\t\tweighta: " << synapse->GetWeight()
           << "\t\tw-value: " << synapse->GetWeightedValue()
           << "\t\tw-delta: " << synapse->GetWeightedDelta()
           << "\t\tl-rate: "  << synapse->GetLearningRate()
           << Endl;
   }
}

//______________________________________________________________________________
void TMVA::TNeuron::PrintActivationEqn()
{
   // print activation equation, for debugging
   if (fActivation != NULL) Log() << kDEBUG << fActivation->GetExpression() << Endl;
   else                     Log() << kDEBUG << "<none>" << Endl;
}

//______________________________________________________________________________
void TMVA::TNeuron::PrintMessage( EMsgType type, TString message)
{
   // print message, for debugging
   Log() << type << message << Endl;
}
<commit_msg> adopted some proposa to avoid excessif memory re-allocation from Peter Elmer<commit_after>// @(#)root/tmva $Id$
// Author: Matt Jachowski

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Class  : TNeuron                                                               *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation (see header for description)                               *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Matt Jachowski  <jachowski@stanford.edu> - Stanford University, USA       *
 *                                                                                *
 * Copyright (c) 2005:                                                            *
 *      CERN, Switzerland                                                         *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

//_______________________________________________________________________
//
// Neuron class used by TMVA artificial neural network methods
//
//_______________________________________________________________________

#include "TH1D.h"

#ifndef ROOT_TMVA_MsgLogger
#include "TMVA/MsgLogger.h"
#endif
#ifndef ROOT_TMVA_TNeuron
#include "TMVA/TNeuron.h"
#endif
#ifndef ROOT_TMVA_TActivation
#include "TMVA/TActivation.h"
#endif
#ifndef ROOT_TMVA_Tools
#include "TMVA/Tools.h"
#endif
#ifndef ROOT_TMVA_TNeuronInput
#include "TMVA/TNeuronInput.h"
#endif

static const Int_t UNINITIALIZED = -1;

using std::vector;

ClassImp(TMVA::TNeuron)

TMVA::MsgLogger* TMVA::TNeuron::fgLogger = 0;

//______________________________________________________________________________
TMVA::TNeuron::TNeuron()
{
   // standard constructor
   if (!fgLogger) fgLogger = new MsgLogger("TNeuron",kDEBUG);
   InitNeuron();
}

TMVA::TNeuron::~TNeuron()
{
   // destructor
   if (fLinksIn != NULL)  delete fLinksIn;
   if (fLinksOut != NULL) delete fLinksOut;
}

void TMVA::TNeuron::InitNeuron()
{
   // initialize the neuron, most variables still need to be set via setters
   fLinksIn = new TObjArray();
   fLinksOut = new TObjArray();
   fValue = UNINITIALIZED;
   fActivationValue = UNINITIALIZED;
   fDelta = UNINITIALIZED;
   fDEDw = UNINITIALIZED;
   fError = UNINITIALIZED;
   fActivation = NULL;
   fForcedValue = kFALSE;
   fInputCalculator = NULL;
}

//______________________________________________________________________________
void TMVA::TNeuron::ForceValue(Double_t value)
{
   // force the value, typically for input and bias neurons
   fValue = value;
   fForcedValue = kTRUE;
}

//______________________________________________________________________________
void TMVA::TNeuron::CalculateValue()
{
   // calculate neuron input
   if (fForcedValue) return;
   fValue = fInputCalculator->GetInput(this);
}

//______________________________________________________________________________
void TMVA::TNeuron::CalculateActivationValue()
{
   // calculate neuron activation/output

   if (fActivation == NULL) {
      PrintMessage( kWARNING ,"No activation equation specified." );
      fActivationValue = UNINITIALIZED;
      return;
   }
   fActivationValue = fActivation->Eval(fValue);
}

//______________________________________________________________________________
void TMVA::TNeuron::CalculateDelta()
{
   // calculate error field

   // no need to adjust input neurons
   if (IsInputNeuron()) {
      fDelta = 0.0;
      return;
   }

   Double_t error;

   // output neuron should have error set all ready
   if (IsOutputNeuron()) error = fError;

   // need to calculate error for any other neuron
   else {
      error = 0.0;
      TSynapse* synapse = NULL;
      //      TObjArrayIter* iter = (TObjArrayIter*)fLinksOut->MakeIterator();
      TObjArrayIter iter(fLinksOut);
      while (true) {
         //synapse = (TSynapse*) iter->Next();
         synapse = (TSynapse*) iter.Next();
         if (synapse == NULL) break;
         error += synapse->GetWeightedDelta();
      }
      //      delete iter;
   }

   fDelta = error * fActivation->EvalDerivative(GetValue());
}

//______________________________________________________________________________
void TMVA::TNeuron::SetInputCalculator(TNeuronInput* calculator)
{
   // set input calculator
   if (fInputCalculator != NULL) delete fInputCalculator;
   fInputCalculator = calculator;
}

//______________________________________________________________________________
void TMVA::TNeuron::SetActivationEqn(TActivation* activation)
{
   // set activation equation
   if (fActivation != NULL) delete fActivation;
   fActivation = activation;
}

//______________________________________________________________________________
void TMVA::TNeuron::AddPreLink(TSynapse* pre)
{
   // add synapse as a pre-link to this neuron
   if (IsInputNeuron()) return;
   fLinksIn->Add(pre);
}

//______________________________________________________________________________
void TMVA::TNeuron::AddPostLink(TSynapse* post)
{
   // add synapse as a post-link to this neuron
   if (IsOutputNeuron()) return;
   fLinksOut->Add(post);
}

//______________________________________________________________________________
void TMVA::TNeuron::DeletePreLinks()
{
   // delete all pre-links
   DeleteLinksArray(fLinksIn);
}

//______________________________________________________________________________
void TMVA::TNeuron::DeleteLinksArray(TObjArray*& links)
{
   // delete an array of TSynapses

   if (links == NULL) return;

   TSynapse* synapse = NULL;
   Int_t numLinks = links->GetEntriesFast();
   for (Int_t i=0; i<numLinks; i++) {
      synapse = (TSynapse*)links->At(i);
      if (synapse != NULL) delete synapse;
   }
   delete links;
   links = NULL;
}

//______________________________________________________________________________
void TMVA::TNeuron::SetError(Double_t error)
{
   // set error, this should only be done for an output neuron
   if (!IsOutputNeuron())
      PrintMessage( kWARNING, "Warning! Setting an error on a non-output neuron is probably not what you want to do." );

   fError = error;
}

//______________________________________________________________________________
void TMVA::TNeuron::UpdateSynapsesBatch()
{
   // update and adjust the pre-synapses for each neuron (input neuron has no pre-synapse)
   // this method should only be called in batch mode

   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->CalculateDelta();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::UpdateSynapsesSequential()
{
   // update the pre-synapses for each neuron (input neuron has no pre-synapse)
   // this method should only be called in sequential mode

   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->InitDelta();
      synapse->CalculateDelta();
      synapse->AdjustWeight();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::AdjustSynapseWeights()
{
   // adjust the pre-synapses' weights for each neuron (input neuron has no pre-synapse)
   // this method should only be called in batch mode

   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->AdjustWeight();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::InitSynapseDeltas()
{
   // initialize the error fields of all pre-neurons
   // this method should only be called in batch mode

   // an input neuron has no pre-weights to adjust
   if (IsInputNeuron()) return;

   TSynapse* synapse = NULL;
   TObjArrayIter* iter = (TObjArrayIter*) fLinksIn->MakeIterator();

   while (true) {
      synapse = (TSynapse*) iter->Next();
      if (synapse == NULL) break;
      synapse->InitDelta();
   }

   delete iter;
}

//______________________________________________________________________________
void TMVA::TNeuron::PrintLinks(TObjArray* links) const
{
   // print an array of TSynapses, for debugging

   if (links == NULL) {
      Log() << kDEBUG << "\t\t\t<none>" << Endl;
      return;
   }

   TSynapse* synapse;

   Int_t numLinks = links->GetEntriesFast();
   for  (Int_t i = 0; i < numLinks; i++) {
      synapse = (TSynapse*)links->At(i);
      Log() << kDEBUG <<
         "\t\t\tweighta: " << synapse->GetWeight()
           << "\t\tw-value: " << synapse->GetWeightedValue()
           << "\t\tw-delta: " << synapse->GetWeightedDelta()
           << "\t\tl-rate: "  << synapse->GetLearningRate()
           << Endl;
   }
}

//______________________________________________________________________________
void TMVA::TNeuron::PrintActivationEqn()
{
   // print activation equation, for debugging
   if (fActivation != NULL) Log() << kDEBUG << fActivation->GetExpression() << Endl;
   else                     Log() << kDEBUG << "<none>" << Endl;
}

//______________________________________________________________________________
void TMVA::TNeuron::PrintMessage( EMsgType type, TString message)
{
   // print message, for debugging
   Log() << type << message << Endl;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: comdep.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 14:12:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifdef MAC
#define private public
#define protected public
#endif

#include "comdep.hxx"

#ifndef _DEBUG_HXX
#include <debug.hxx>
#endif
#ifndef _LIST_HXX
#include <list.hxx>
#endif
#ifndef _FSYS_HXX
#include <fsys.hxx>
#endif

DBG_NAMEEX( DirEntry );

//--------------------------------------------------------------------

#if defined( DOS ) || defined( WIN )

#ifdef MSC
#include "dosmsc.cxx"
#endif

#if defined( BLC ) || defined( TCPP )
#include "dosblc.cxx"
#endif

#ifdef ZTC
#include "dosztc.cxx"
#endif

#else

#if defined( WNT ) && !defined( WTC )
#include "wntmsc.cxx"
#endif

#ifdef UNX
#include "unx.cxx"
#endif

#ifdef PM2
#include "os2.cxx"
#endif

#ifdef MAC
#include "mac.cxx"
#endif

#endif

<commit_msg>INTEGRATION: CWS warnings01 (1.2.8); FILE MERGED 2005/10/13 13:24:26 sb 1.2.8.1: #i53898# Removed code for obsolete platforms.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: comdep.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 13:38:30 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "comdep.hxx"

#ifndef _DEBUG_HXX
#include <debug.hxx>
#endif
#ifndef _LIST_HXX
#include <list.hxx>
#endif
#ifndef _FSYS_HXX
#include <fsys.hxx>
#endif

DBG_NAMEEX( DirEntry )

#if defined UNX
#include "unx.cxx"
#elif defined WNT
#include "wntmsc.cxx"
#endif
<|endoftext|>


<commit_before><commit_msg>ByteString->rtl::OString[Buffer]<commit_after><|endoftext|>


<commit_before><commit_msg>coverity#705324 Missing break in switch<commit_after><|endoftext|>


<commit_before>/*
All Hands On Deck
    Copyright (C) 2015 Vladimir "allejo" Jimenez

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

    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "bzfsAPI.h"
#include "plugin_utils.h"

static void killAllPlayers ()
{
    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    for (unsigned int i = 0; i < playerList->size(); i++)
    {
        int playerID = playerList->get(i);

        if (bz_getPlayerByIndex(playerID)->spawned && bz_killPlayer(playerID, true))
            bz_setPlayerLosses(playerID, bz_getPlayerLosses(playerID) - 1);
    }

    bz_deleteIntList(playerList);
}

static void sendToPlayers (bz_eTeamType team, std::string message)
{
    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    for (unsigned int i = 0; i < playerList->size(); i++)
    {
        int playerID = playerList->get(i);

        if (bz_getPlayerByIndex(playerID)->team == team)
            bz_sendTextMessagef(playerID, playerID, message.c_str());
    }

    bz_deleteIntList(playerList);
}

static std::string teamColorLiteral (bz_eTeamType teamColor)
{
    switch (teamColor)
    {
        case eBlueTeam:
            return "Blue";

        case eGreenTeam:
            return "Green";

        case ePurpleTeam:
            return "Purple";

        case eRedTeam:
            return "Red";

        default:
            return "Rogue";
    }
}

static std::string teamToTeamFlag (bz_eTeamType team)
{
  switch (team)
  {
    case eBlueTeam:
      return "B*";

    case eGreenTeam:
      return "G*";

    case ePurpleTeam:
      return "P*";

    case eRedTeam:
      return "R*";

    default:
      return "";
  }
}

class AhodZone : public bz_CustomZoneObject
{
public:
    AhodZone() : bz_CustomZoneObject() {}
};

class AllHandsOnDeck : public bz_Plugin, bz_CustomMapObjectHandler
{
public:
    virtual const char* Name () {return "All Hands On Deck";}
    virtual void Init (const char* config);
    virtual void Event (bz_EventData *eventData);
    virtual void Cleanup (void);
    virtual bool MapObject (bz_ApiString object, bz_CustomMapObjectInfo *data);

    virtual bool isInsideAhodZone (int playerID);
    virtual bool isEntireTeamOnBase (bz_eTeamType team);
    virtual bool doesTeamHaveEnemyFlag (bz_eTeamType team, bz_eTeamType enemy);

    AhodZone ahodZone;

    bz_eTeamType teamOne, teamTwo;
};

BZ_PLUGIN(AllHandsOnDeck)

void AllHandsOnDeck::Init (const char* /* commandLine */)
{
    bz_registerCustomMapObject("AHOD", this);

    teamOne = eNoTeam;
    teamTwo = eNoTeam;

    for (bz_eTeamType t = eRedTeam; t <= ePurpleTeam; t = (bz_eTeamType) (t + 1))
    {
        if (bz_getTeamPlayerLimit(t) > 0)
        {
            if (teamOne == eNoTeam)
                teamOne = t;
            else if (teamTwo == eNoTeam)
                teamTwo = t;
        }
    }

    Register(bz_eAllowCTFCaptureEvent);
    Register(bz_ePlayerJoinEvent);
    Register(bz_ePlayerPausedEvent);
    Register(bz_eTickEvent);
}

void AllHandsOnDeck::Cleanup (void)
{
    Flush();

    bz_removeCustomMapObject("AHOD");
}

bool AllHandsOnDeck::MapObject (bz_ApiString object, bz_CustomMapObjectInfo *data)
{
    if (object != "AHOD" || !data)
    {
        return false;
    }

    ahodZone.handleDefaultOptions(data);

    return true;
}

void AllHandsOnDeck::Event (bz_EventData *eventData)
{
    switch (eventData->eventType)
    {
        case bz_eAllowCTFCaptureEvent: // This event is called each time a flag is about to be captured
        {
            bz_AllowCTFCaptureEventData_V1* allowCtfData = (bz_AllowCTFCaptureEventData_V1*)eventData;

            allowCtfData->allow = false;
        }
        break;

        case bz_ePlayerJoinEvent: // This event is called each time a player joins the game
        {
            bz_PlayerJoinPartEventData_V1* joinData = (bz_PlayerJoinPartEventData_V1*)eventData;
            int playerID = joinData->playerID;

            bz_sendTextMessage(playerID, playerID, "********************************************************************");
            bz_sendTextMessage(playerID, playerID, " ");
            bz_sendTextMessage(playerID, playerID, "  --- How To Play ---");
            bz_sendTextMessage(playerID, playerID, "     Take the enemy flag to the neutral (green) base along with your");
            bz_sendTextMessage(playerID, playerID, "     entire team in order to cap. If any player is missing, you will");
            bz_sendTextMessage(playerID, playerID, "     not be able to cap. Team work matters!");
            bz_sendTextMessage(playerID, playerID, " ");
            bz_sendTextMessage(playerID, playerID, "********************************************************************");
        }
        break;

        case bz_ePlayerPausedEvent: // This event is called each time a playing tank is paused
        {
            bz_PlayerPausedEventData_V1* pauseData = (bz_PlayerPausedEventData_V1*)eventData;

            if (isInsideAhodZone(pauseData->playerID) && pauseData->pause)
            {
                bz_killPlayer(pauseData->playerID, false);
                bz_sendTextMessage(BZ_SERVER, pauseData->playerID, "Pausing in the AHOD zone is not permitted.");
            }
        }
        break;

        case bz_eTickEvent: // This event is called once for each BZFS main loop
        {
	  // AHOD is only enabled if there are at least 2 players per team
	  if (bz_getTeamCount(teamOne) < 2 || bz_getTeamCount(teamTwo) < 2)
	  {
	    return;
	  }

	  bool teamOneAhod = isEntireTeamOnBase(teamOne);
	  bool teamTwoAhod = isEntireTeamOnBase(teamTwo);

	    if (teamOneAhod || teamTwoAhod)
	    {
	      bool teamOneHasEnemyFlag = doesTeamHaveEnemyFlag(teamOne, teamTwo);
	      bool teamTwoHasEnemyFlag = doesTeamHaveEnemyFlag(teamTwo, teamOne);

	      if (teamOneHasEnemyFlag || teamTwoHasEnemyFlag) {
		if ((teamOneAhod && teamOneHasEnemyFlag) || (teamTwoAhod && teamTwoHasEnemyFlag))
		{
		  bz_eTeamType victor = (teamOneHasEnemyFlag) ? teamOne : teamTwo;
		  bz_eTeamType loser  = (teamOneHasEnemyFlag) ? teamTwo : teamOne;

		  killAllPlayers();
		  bz_incrementTeamWins(victor, 1);
		  bz_incrementTeamLosses(loser, 1);
		  bz_resetFlags(false);

		  sendToPlayers(loser, std::string("Team flag captured by the " + teamColorLiteral(victor) + " team!"));
		  sendToPlayers(victor, std::string("Great team work! Don't let them capture your flag!"));
		}
	      }
            }
        }
        break;

        default: break;
    }
}

bool AllHandsOnDeck::doesTeamHaveEnemyFlag(bz_eTeamType team, bz_eTeamType enemy)
{
    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    bool doesHaveEnemyFlag = false;

    for (unsigned int i = 0; i < playerList->size(); i++ )
    {
        int playerID = playerList->get(i);
        const char* cFlag = bz_getPlayerFlag(playerID);
        std::string teamFlag = (cFlag == NULL) ? "" : cFlag;

        if (bz_getPlayerTeam(playerID) == team && teamFlag == teamToTeamFlag(enemy))
        {
            doesHaveEnemyFlag = true;
	    break;
        }
    }

    bz_deleteIntList(playerList);

    return doesHaveEnemyFlag;
}

bool AllHandsOnDeck::isInsideAhodZone (int playerID)
{
    bz_BasePlayerRecord* pr = bz_getPlayerByIndex(playerID);
    bool isInside = false;

    if (pr && ahodZone.pointInZone(pr->lastKnownState.pos) && pr->spawned && !pr->lastKnownState.falling)
    {
        isInside = true;
    }

    bz_freePlayerRecord(pr);

    return isInside;
}

bool AllHandsOnDeck::isEntireTeamOnBase (bz_eTeamType team)
{
  if (bz_getTeamCount(teamTwo) < 2)
  {
    return false;
  }

    bool entireTeamOnBase = true;

    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    for (unsigned int i = 0; i < playerList->size(); i++)
    {
        int playerID = playerList->get(i);

        if (bz_getPlayerTeam(playerID) == team && !isInsideAhodZone(playerID))
        {
            entireTeamOnBase = false;
            break;
        }
    }

    bz_deleteIntList(playerList);

    return entireTeamOnBase;
}<commit_msg>Fix whitespace issue<commit_after>/*
All Hands On Deck
    Copyright (C) 2015 Vladimir "allejo" Jimenez

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

    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "bzfsAPI.h"
#include "plugin_utils.h"

static void killAllPlayers ()
{
    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    for (unsigned int i = 0; i < playerList->size(); i++)
    {
        int playerID = playerList->get(i);

        if (bz_getPlayerByIndex(playerID)->spawned && bz_killPlayer(playerID, true))
        {
            bz_setPlayerLosses(playerID, bz_getPlayerLosses(playerID) - 1);
        }
    }

    bz_deleteIntList(playerList);
}

static void sendToPlayers (bz_eTeamType team, std::string message)
{
    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    for (unsigned int i = 0; i < playerList->size(); i++)
    {
        int playerID = playerList->get(i);

        if (bz_getPlayerByIndex(playerID)->team == team)
        {
            bz_sendTextMessagef(playerID, playerID, message.c_str());
        }
    }

    bz_deleteIntList(playerList);
}

static std::string teamColorLiteral (bz_eTeamType teamColor)
{
    switch (teamColor)
    {
        case eBlueTeam:
            return "Blue";

        case eGreenTeam:
            return "Green";

        case ePurpleTeam:
            return "Purple";

        case eRedTeam:
            return "Red";

        default:
            return "Rogue";
    }
}

static std::string teamToTeamFlag (bz_eTeamType team)
{
  switch (team)
  {
    case eBlueTeam:
      return "B*";

    case eGreenTeam:
      return "G*";

    case ePurpleTeam:
      return "P*";

    case eRedTeam:
      return "R*";

    default:
      return "";
  }
}

class AhodZone : public bz_CustomZoneObject
{
public:
    AhodZone() : bz_CustomZoneObject() {}
};

class AllHandsOnDeck : public bz_Plugin, bz_CustomMapObjectHandler
{
public:
    virtual const char* Name () {return "All Hands On Deck";}
    virtual void Init (const char* config);
    virtual void Event (bz_EventData *eventData);
    virtual void Cleanup (void);
    virtual bool MapObject (bz_ApiString object, bz_CustomMapObjectInfo *data);

    virtual bool isInsideAhodZone (int playerID);
    virtual bool isEntireTeamOnBase (bz_eTeamType team);
    virtual bool doesTeamHaveEnemyFlag (bz_eTeamType team, bz_eTeamType enemy);

    AhodZone ahodZone;

    bz_eTeamType teamOne, teamTwo;
};

BZ_PLUGIN(AllHandsOnDeck)

void AllHandsOnDeck::Init (const char* /* commandLine */)
{
    bz_registerCustomMapObject("AHOD", this);

    teamOne = eNoTeam;
    teamTwo = eNoTeam;

    for (bz_eTeamType t = eRedTeam; t <= ePurpleTeam; t = (bz_eTeamType) (t + 1))
    {
        if (bz_getTeamPlayerLimit(t) > 0)
        {
            if      (teamOne == eNoTeam) teamOne = t;
            else if (teamTwo == eNoTeam) teamTwo = t;
        }
    }

    Register(bz_eAllowCTFCaptureEvent);
    Register(bz_ePlayerJoinEvent);
    Register(bz_ePlayerPausedEvent);
    Register(bz_eTickEvent);
}

void AllHandsOnDeck::Cleanup (void)
{
    Flush();

    bz_removeCustomMapObject("AHOD");
}

bool AllHandsOnDeck::MapObject (bz_ApiString object, bz_CustomMapObjectInfo *data)
{
    if (object != "AHOD" || !data)
    {
        return false;
    }

    ahodZone.handleDefaultOptions(data);

    return true;
}

void AllHandsOnDeck::Event (bz_EventData *eventData)
{
    switch (eventData->eventType)
    {
        case bz_eAllowCTFCaptureEvent: // This event is called each time a flag is about to be captured
        {
            bz_AllowCTFCaptureEventData_V1* allowCtfData = (bz_AllowCTFCaptureEventData_V1*)eventData;

            allowCtfData->allow = false;
        }
        break;

        case bz_ePlayerJoinEvent: // This event is called each time a player joins the game
        {
            bz_PlayerJoinPartEventData_V1* joinData = (bz_PlayerJoinPartEventData_V1*)eventData;
            int playerID = joinData->playerID;

            bz_sendTextMessage(playerID, playerID, "********************************************************************");
            bz_sendTextMessage(playerID, playerID, " ");
            bz_sendTextMessage(playerID, playerID, "  --- How To Play ---");
            bz_sendTextMessage(playerID, playerID, "     Take the enemy flag to the neutral (green) base along with your");
            bz_sendTextMessage(playerID, playerID, "     entire team in order to cap. If any player is missing, you will");
            bz_sendTextMessage(playerID, playerID, "     not be able to cap. Team work matters!");
            bz_sendTextMessage(playerID, playerID, " ");
            bz_sendTextMessage(playerID, playerID, "********************************************************************");
        }
        break;

        case bz_ePlayerPausedEvent: // This event is called each time a playing tank is paused
        {
            bz_PlayerPausedEventData_V1* pauseData = (bz_PlayerPausedEventData_V1*)eventData;

            if (isInsideAhodZone(pauseData->playerID) && pauseData->pause)
            {
                bz_killPlayer(pauseData->playerID, false);
                bz_sendTextMessage(BZ_SERVER, pauseData->playerID, "Pausing in the AHOD zone is not permitted.");
            }
        }
        break;

        case bz_eTickEvent: // This event is called once for each BZFS main loop
        {
            // AHOD is only enabled if there are at least 2 players per team
            if (bz_getTeamCount(teamOne) < 2 || bz_getTeamCount(teamTwo) < 2)
            {
                return;
            }

            bool teamOneAhod = isEntireTeamOnBase(teamOne);
            bool teamTwoAhod = isEntireTeamOnBase(teamTwo);

            if (teamOneAhod || teamTwoAhod)
            {
                bool teamOneHasEnemyFlag = doesTeamHaveEnemyFlag(teamOne, teamTwo);
                bool teamTwoHasEnemyFlag = doesTeamHaveEnemyFlag(teamTwo, teamOne);

                if (teamOneHasEnemyFlag || teamTwoHasEnemyFlag)
                {
                    if ((teamOneAhod && teamOneHasEnemyFlag) || (teamTwoAhod && teamTwoHasEnemyFlag))
                    {
                        bz_eTeamType victor = (teamOneHasEnemyFlag) ? teamOne : teamTwo;
                        bz_eTeamType loser  = (teamOneHasEnemyFlag) ? teamTwo : teamOne;

                        killAllPlayers();
                        bz_incrementTeamWins(victor, 1);
                        bz_incrementTeamLosses(loser, 1);
                        bz_resetFlags(false);

                        sendToPlayers(loser, std::string("Team flag captured by the " + teamColorLiteral(victor) + " team!"));
                        sendToPlayers(victor, std::string("Great team work! Don't let them capture your flag!"));
                    }
                }
            }
        }
        break;

        default: break;
    }
}

bool AllHandsOnDeck::doesTeamHaveEnemyFlag(bz_eTeamType team, bz_eTeamType enemy)
{
    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    bool doesHaveEnemyFlag = false;

    for (unsigned int i = 0; i < playerList->size(); i++ )
    {
        int playerID = playerList->get(i);
        const char* cFlag = bz_getPlayerFlag(playerID);
        std::string teamFlag = (cFlag == NULL) ? "" : cFlag;

        if (bz_getPlayerTeam(playerID) == team && teamFlag == teamToTeamFlag(enemy))
        {
            doesHaveEnemyFlag = true;
            break;
        }
    }

    bz_deleteIntList(playerList);

    return doesHaveEnemyFlag;
}

bool AllHandsOnDeck::isInsideAhodZone (int playerID)
{
    bz_BasePlayerRecord* pr = bz_getPlayerByIndex(playerID);
    bool isInside = false;

    if (pr && ahodZone.pointInZone(pr->lastKnownState.pos) && pr->spawned && !pr->lastKnownState.falling)
    {
        isInside = true;
    }

    bz_freePlayerRecord(pr);

    return isInside;
}

bool AllHandsOnDeck::isEntireTeamOnBase (bz_eTeamType team)
{
    if (bz_getTeamCount(teamTwo) < 2)
    {
        return false;
    }

    bool entireTeamOnBase = true;

    bz_APIIntList *playerList = bz_newIntList();
    bz_getPlayerIndexList(playerList);

    for (unsigned int i = 0; i < playerList->size(); i++)
    {
        int playerID = playerList->get(i);

        if (bz_getPlayerTeam(playerID) == team && !isInsideAhodZone(playerID))
        {
            entireTeamOnBase = false;
            break;
        }
    }

    bz_deleteIntList(playerList);

    return entireTeamOnBase;
}<|endoftext|>