<commit_before>#include "yahttp.hpp"

namespace YaHTTP {
  template <class T>
  int AsyncLoader<T>::feed(const std::string& somedata) {
    buffer.append(somedata);
    while(state < 2) {
      int cr=0;
      pos = buffer.find_first_of("\n");
      // need to find CRLF in buffer
      if (pos == std::string::npos) return false;
      if (pos>0 && buffer[pos-1]=='\r')
        cr=1;
      std::string line(buffer.begin(), buffer.begin()+pos-cr); // exclude CRLF
      buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer including CRLF

      if (state == 0) { // startup line
        if (target->kind == YAHTTP_TYPE_REQUEST) {
          std::string ver;
          std::string tmpurl;
          std::istringstream iss(line);
          iss >> target->method >> tmpurl >> ver;
          if (ver.size() == 0)
            target->version = 9;
          else if (ver.find("HTTP/0.9") == 0)
            target->version = 9;
          else if (ver.find("HTTP/1.0") == 0)
            target->version = 10;
          else if (ver.find("HTTP/1.1") == 0)
            target->version = 11;
          else
            throw ParseError("HTTP version not supported");
          // uppercase the target method
          std::transform(target->method.begin(), target->method.end(), target->method.begin(), ::toupper);
          target->url.parse(tmpurl);
          target->getvars = Utility::parseUrlParameters(target->url.parameters);
          state = 1;
        } else if(target->kind == YAHTTP_TYPE_RESPONSE) {
          std::string ver;
          std::istringstream iss(line);
          std::string::size_type pos1;
          iss >> ver >> target->status;
          std::getline(iss, target->statusText);
          pos1=0;
          while(pos1 < target->statusText.size() && ::isspace(target->statusText.at(pos1))) pos1++;
          target->statusText = target->statusText.substr(pos1);
          if ((pos1 = target->statusText.find("\r")) != std::string::npos) {
            target->statusText = target->statusText.substr(0, pos1-1);
          }
          if (ver.size() == 0) {
            target->version = 9;
          } else if (ver.find("HTTP/0.9") == 0)
            target->version = 9;
          else if (ver.find("HTTP/1.0") == 0)
            target->version = 10;
          else if (ver.find("HTTP/1.1") == 0)
            target->version = 11;
          else
            throw ParseError("HTTP version not supported");
          state = 1;
        }
      } else if (state == 1) {
        std::string key,value;
        size_t pos;
        if (line.empty()) {
          chunked = (target->headers.find("transfer-encoding") != target->headers.end() && target->headers["transfer-encoding"] == "chunked");
          state = 2;
          break;
        }
        // split headers
        if ((pos = line.find(": ")) == std::string::npos)
          throw ParseError("Malformed header line");
        key = line.substr(0, pos);
        value = line.substr(pos+2);
        for(std::string::iterator it=key.begin(); it != key.end(); it++)
          if (std::isspace(*it))
            throw ParseError("Header key contains whitespace which is not allowed by RFC");

        Utility::trim(value);
        std::transform(key.begin(), key.end(), key.begin(), ::tolower);
        // is it already defined

        if ((key == "set-cookie" && target->kind == YAHTTP_TYPE_RESPONSE) ||
            (key == "cookie" && target->kind == YAHTTP_TYPE_REQUEST)) {
          target->jar.parseCookieHeader(value);
        } else {
          if (key == "host" && target->kind == YAHTTP_TYPE_REQUEST) {
            // maybe it contains port?
            if ((pos = value.find(":")) == std::string::npos) {
              target->url.host = value;
            } else {
              target->url.host = value.substr(0, pos);
              target->url.port = ::atoi(value.substr(pos).c_str());
            }
          }
          if (target->headers.find(key) != target->headers.end()) {
            target->headers[key] = target->headers[key] + ";" + value;
          } else {
            target->headers[key] = value;
          }
        }
      }
    }

    minbody = 0;
    // check for expected body size
    if (target->kind == YAHTTP_TYPE_REQUEST) maxbody = target->max_request_size;
    else if (target->kind == YAHTTP_TYPE_RESPONSE) maxbody = target->max_response_size;
    else maxbody = 0;

    if (!chunked) {
      if (target->headers.find("content-length") != target->headers.end()) {
        std::istringstream maxbodyS(target->headers["content-length"]);
        maxbodyS >> minbody;
        maxbody = minbody;
      }
      if (minbody < 1) return true; // guess there isn't anything left.
      if (target->kind == YAHTTP_TYPE_REQUEST && static_cast<ssize_t>(minbody) > target->max_request_size) throw ParseError("Max request body size exceeded");
      else if (target->kind == YAHTTP_TYPE_RESPONSE && static_cast<ssize_t>(minbody) > target->max_response_size) throw ParseError("Max response body size exceeded");
    }

    if (maxbody == 0) hasBody = false;
    else hasBody = true;

    if (buffer.size() == 0) return ready();

    while(buffer.size() > 0) {
      if (chunked) {
        if (chunk_size == 0) {
          char buf[100];
          // read chunk length
          if ((pos = buffer.find('\n')) == std::string::npos) return false;
          if (pos > 99)
            throw ParseError("Impossible chunk_size");
          buffer.copy(buf, pos);
          buf[pos]=0; // just in case...
          buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer
          sscanf(buf, "%x", &chunk_size);
          if (!chunk_size) { state = 3; break; } // last chunk
        } else {
          int crlf=1;
          if (buffer.size() < static_cast<size_t>(chunk_size+1)) return false; // expect newline
          if (buffer.at(chunk_size) == '\r') {
            if (buffer.size() < static_cast<size_t>(chunk_size+2) || buffer.at(chunk_size+1) != '\n') return false; // expect newline after carriage return
            crlf=2;
          } else if (buffer.at(chunk_size) != '\n') return false;
          std::string tmp = buffer.substr(0, chunk_size);
          buffer.erase(buffer.begin(), buffer.begin()+chunk_size+crlf);
          bodybuf << tmp;
          chunk_size = 0;
          if (buffer.size() == 0) break; // just in case
        }
      } else {
        if (bodybuf.str().length() + buffer.length() > maxbody)
          bodybuf << buffer.substr(0, maxbody - bodybuf.str().length());
        else
          bodybuf << buffer;
        buffer = "";
      }
    }

    if (chunk_size!=0) return false; // need more data

    return ready();
  };

  void HTTPBase::write(std::ostream& os) const {
    if (kind == YAHTTP_TYPE_REQUEST) {
      std::ostringstream getparmbuf;
      std::string getparms;
      // prepare URL
      for(strstr_map_t::const_iterator i = getvars.begin(); i != getvars.end(); i++) {
        getparmbuf << Utility::encodeURL(i->first, false) << "=" << Utility::encodeURL(i->second, false) << "&";
      }
      if (getparmbuf.str().length() > 0)
        getparms = "?" + std::string(getparmbuf.str().begin(), getparmbuf.str().end() - 1);
      else
        getparms = "";
      os << method << " " << url.path << getparms << " HTTP/" << versionStr(this->version);
    } else if (kind == YAHTTP_TYPE_RESPONSE) {
      os << "HTTP/" << versionStr(this->version) << " " << status << " ";
      if (statusText.empty())
        os << Utility::status2text(status);
      else
        os << statusText;
    }
    os << "\r\n";

    bool cookieSent = false;
    bool sendChunked = false;
    bool hasBody = true;

    if (this->version > 10) { // 1.1 or better
      if (headers.find("content-length") == headers.end()) {
        // must use chunked on response
        sendChunked = (kind == YAHTTP_TYPE_RESPONSE);
        if ((headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second != "chunked")) {
          throw YaHTTP::Error("Transfer-encoding must be chunked, or Content-Length defined");
        }
        if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) {
          sendChunked = true;
          os << "Transfer-Encoding: chunked\r\n";
        }
      } else {
        hasBody = (headers.find("content-length")->second != "0");
        if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) {
          sendChunked = hasBody;
          if (sendChunked)
            os << "Transfer-Encoding: chunked\r\n";
        } else if (headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second == "chunked") {
          sendChunked = hasBody;
        }
      }
    }

    // write headers
    strstr_map_t::const_iterator iter = headers.begin();
    while(iter != headers.end()) {
      if (iter->first == "host" && kind != YAHTTP_TYPE_REQUEST) { iter++; continue; }
      if (iter->first == "transfer-encoding" && sendChunked) { iter++; continue; }
      std::string header = Utility::camelizeHeader(iter->first);
      if (header == "Cookie" || header == "Set-Cookie") cookieSent = true;
      os << Utility::camelizeHeader(iter->first) << ": " << iter->second << "\r\n";
      iter++;
    }
    if (!cookieSent && jar.cookies.size() > 0) { // write cookies
      for(strcookie_map_t::const_iterator i = jar.cookies.begin(); i != jar.cookies.end(); i++) {
        if (kind == YAHTTP_TYPE_REQUEST) {
          os << "Cookie: ";
        } else {
          os << "Set-Cookie: ";
        }
        os << i->second.str() << "\r\n";
      }
    }
    os << "\r\n";
#ifdef HAVE_CPP_FUNC_PTR
    this->renderer(this, os, sendChunked);
#else
    SendbodyRenderer r;
    r(this, os, chunked)
#endif
  };

  std::ostream& operator<<(std::ostream& os, const Response &resp) {
    resp.write(os);
    return os;
  };

  std::istream& operator>>(std::istream& is, Response &resp) {
    YaHTTP::AsyncResponseLoader arl;
    arl.initialize(&resp);
    while(is.good()) {
      char buf[1024];
      is.read(buf, 1024);
      if (is.gcount()>0) { // did we actually read anything
        is.clear();
        if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed
      }
    }
    // throw unless ready
    if (arl.ready() == false)
      throw ParseError("Was not able to extract a valid Response from stream");
    arl.finalize();
    return is;
  };

  std::ostream& operator<<(std::ostream& os, const Request &req) {
    req.write(os);
    return os;
  };

  std::istream& operator>>(std::istream& is, Request &req) {
    YaHTTP::AsyncRequestLoader arl;
    arl.initialize(&req);
    while(is.good()) {
      char buf[1024];
      is.read(buf, 1024);
      if (is.gcount()) { // did we actually read anything
        is.clear();
        if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed
      }
    }
    if (arl.ready() == false)
      throw ParseError("Was not able to extract a valid Request from stream");
    arl.finalize();
    return is;
  };
};
<commit_msg>Fix unsafe use of str()<commit_after>#include "yahttp.hpp"

namespace YaHTTP {
  template <class T>
  int AsyncLoader<T>::feed(const std::string& somedata) {
    buffer.append(somedata);
    while(state < 2) {
      int cr=0;
      pos = buffer.find_first_of("\n");
      // need to find CRLF in buffer
      if (pos == std::string::npos) return false;
      if (pos>0 && buffer[pos-1]=='\r')
        cr=1;
      std::string line(buffer.begin(), buffer.begin()+pos-cr); // exclude CRLF
      buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer including CRLF

      if (state == 0) { // startup line
        if (target->kind == YAHTTP_TYPE_REQUEST) {
          std::string ver;
          std::string tmpurl;
          std::istringstream iss(line);
          iss >> target->method >> tmpurl >> ver;
          if (ver.size() == 0)
            target->version = 9;
          else if (ver.find("HTTP/0.9") == 0)
            target->version = 9;
          else if (ver.find("HTTP/1.0") == 0)
            target->version = 10;
          else if (ver.find("HTTP/1.1") == 0)
            target->version = 11;
          else
            throw ParseError("HTTP version not supported");
          // uppercase the target method
          std::transform(target->method.begin(), target->method.end(), target->method.begin(), ::toupper);
          target->url.parse(tmpurl);
          target->getvars = Utility::parseUrlParameters(target->url.parameters);
          state = 1;
        } else if(target->kind == YAHTTP_TYPE_RESPONSE) {
          std::string ver;
          std::istringstream iss(line);
          std::string::size_type pos1;
          iss >> ver >> target->status;
          std::getline(iss, target->statusText);
          pos1=0;
          while(pos1 < target->statusText.size() && ::isspace(target->statusText.at(pos1))) pos1++;
          target->statusText = target->statusText.substr(pos1);
          if ((pos1 = target->statusText.find("\r")) != std::string::npos) {
            target->statusText = target->statusText.substr(0, pos1-1);
          }
          if (ver.size() == 0) {
            target->version = 9;
          } else if (ver.find("HTTP/0.9") == 0)
            target->version = 9;
          else if (ver.find("HTTP/1.0") == 0)
            target->version = 10;
          else if (ver.find("HTTP/1.1") == 0)
            target->version = 11;
          else
            throw ParseError("HTTP version not supported");
          state = 1;
        }
      } else if (state == 1) {
        std::string key,value;
        size_t pos;
        if (line.empty()) {
          chunked = (target->headers.find("transfer-encoding") != target->headers.end() && target->headers["transfer-encoding"] == "chunked");
          state = 2;
          break;
        }
        // split headers
        if ((pos = line.find(": ")) == std::string::npos)
          throw ParseError("Malformed header line");
        key = line.substr(0, pos);
        value = line.substr(pos+2);
        for(std::string::iterator it=key.begin(); it != key.end(); it++)
          if (std::isspace(*it))
            throw ParseError("Header key contains whitespace which is not allowed by RFC");

        Utility::trim(value);
        std::transform(key.begin(), key.end(), key.begin(), ::tolower);
        // is it already defined

        if ((key == "set-cookie" && target->kind == YAHTTP_TYPE_RESPONSE) ||
            (key == "cookie" && target->kind == YAHTTP_TYPE_REQUEST)) {
          target->jar.parseCookieHeader(value);
        } else {
          if (key == "host" && target->kind == YAHTTP_TYPE_REQUEST) {
            // maybe it contains port?
            if ((pos = value.find(":")) == std::string::npos) {
              target->url.host = value;
            } else {
              target->url.host = value.substr(0, pos);
              target->url.port = ::atoi(value.substr(pos).c_str());
            }
          }
          if (target->headers.find(key) != target->headers.end()) {
            target->headers[key] = target->headers[key] + ";" + value;
          } else {
            target->headers[key] = value;
          }
        }
      }
    }

    minbody = 0;
    // check for expected body size
    if (target->kind == YAHTTP_TYPE_REQUEST) maxbody = target->max_request_size;
    else if (target->kind == YAHTTP_TYPE_RESPONSE) maxbody = target->max_response_size;
    else maxbody = 0;

    if (!chunked) {
      if (target->headers.find("content-length") != target->headers.end()) {
        std::istringstream maxbodyS(target->headers["content-length"]);
        maxbodyS >> minbody;
        maxbody = minbody;
      }
      if (minbody < 1) return true; // guess there isn't anything left.
      if (target->kind == YAHTTP_TYPE_REQUEST && static_cast<ssize_t>(minbody) > target->max_request_size) throw ParseError("Max request body size exceeded");
      else if (target->kind == YAHTTP_TYPE_RESPONSE && static_cast<ssize_t>(minbody) > target->max_response_size) throw ParseError("Max response body size exceeded");
    }

    if (maxbody == 0) hasBody = false;
    else hasBody = true;

    if (buffer.size() == 0) return ready();

    while(buffer.size() > 0) {
      if (chunked) {
        if (chunk_size == 0) {
          char buf[100];
          // read chunk length
          if ((pos = buffer.find('\n')) == std::string::npos) return false;
          if (pos > 99)
            throw ParseError("Impossible chunk_size");
          buffer.copy(buf, pos);
          buf[pos]=0; // just in case...
          buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer
          sscanf(buf, "%x", &chunk_size);
          if (!chunk_size) { state = 3; break; } // last chunk
        } else {
          int crlf=1;
          if (buffer.size() < static_cast<size_t>(chunk_size+1)) return false; // expect newline
          if (buffer.at(chunk_size) == '\r') {
            if (buffer.size() < static_cast<size_t>(chunk_size+2) || buffer.at(chunk_size+1) != '\n') return false; // expect newline after carriage return
            crlf=2;
          } else if (buffer.at(chunk_size) != '\n') return false;
          std::string tmp = buffer.substr(0, chunk_size);
          buffer.erase(buffer.begin(), buffer.begin()+chunk_size+crlf);
          bodybuf << tmp;
          chunk_size = 0;
          if (buffer.size() == 0) break; // just in case
        }
      } else {
        if (bodybuf.str().length() + buffer.length() > maxbody)
          bodybuf << buffer.substr(0, maxbody - bodybuf.str().length());
        else
          bodybuf << buffer;
        buffer = "";
      }
    }

    if (chunk_size!=0) return false; // need more data

    return ready();
  };

  void HTTPBase::write(std::ostream& os) const {
    if (kind == YAHTTP_TYPE_REQUEST) {
      std::ostringstream getparmbuf;
      std::string getparms;
      // prepare URL
      for(strstr_map_t::const_iterator i = getvars.begin(); i != getvars.end(); i++) {
        getparmbuf << Utility::encodeURL(i->first, false) << "=" << Utility::encodeURL(i->second, false) << "&";
      }
      if (getparmbuf.str().length() > 0) {
        std::string buf = getparmbuf.str();
        getparms = "?" + std::string(buf.begin(), buf.end() - 1);
      }
      else
        getparms = "";
      os << method << " " << url.path << getparms << " HTTP/" << versionStr(this->version);
    } else if (kind == YAHTTP_TYPE_RESPONSE) {
      os << "HTTP/" << versionStr(this->version) << " " << status << " ";
      if (statusText.empty())
        os << Utility::status2text(status);
      else
        os << statusText;
    }
    os << "\r\n";

    bool cookieSent = false;
    bool sendChunked = false;
    bool hasBody = true;

    if (this->version > 10) { // 1.1 or better
      if (headers.find("content-length") == headers.end()) {
        // must use chunked on response
        sendChunked = (kind == YAHTTP_TYPE_RESPONSE);
        if ((headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second != "chunked")) {
          throw YaHTTP::Error("Transfer-encoding must be chunked, or Content-Length defined");
        }
        if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) {
          sendChunked = true;
          os << "Transfer-Encoding: chunked\r\n";
        }
      } else {
        hasBody = (headers.find("content-length")->second != "0");
        if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) {
          sendChunked = hasBody;
          if (sendChunked)
            os << "Transfer-Encoding: chunked\r\n";
        } else if (headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second == "chunked") {
          sendChunked = hasBody;
        }
      }
    }

    // write headers
    strstr_map_t::const_iterator iter = headers.begin();
    while(iter != headers.end()) {
      if (iter->first == "host" && kind != YAHTTP_TYPE_REQUEST) { iter++; continue; }
      if (iter->first == "transfer-encoding" && sendChunked) { iter++; continue; }
      std::string header = Utility::camelizeHeader(iter->first);
      if (header == "Cookie" || header == "Set-Cookie") cookieSent = true;
      os << Utility::camelizeHeader(iter->first) << ": " << iter->second << "\r\n";
      iter++;
    }
    if (!cookieSent && jar.cookies.size() > 0) { // write cookies
      for(strcookie_map_t::const_iterator i = jar.cookies.begin(); i != jar.cookies.end(); i++) {
        if (kind == YAHTTP_TYPE_REQUEST) {
          os << "Cookie: ";
        } else {
          os << "Set-Cookie: ";
        }
        os << i->second.str() << "\r\n";
      }
    }
    os << "\r\n";
#ifdef HAVE_CPP_FUNC_PTR
    this->renderer(this, os, sendChunked);
#else
    SendbodyRenderer r;
    r(this, os, chunked)
#endif
  };

  std::ostream& operator<<(std::ostream& os, const Response &resp) {
    resp.write(os);
    return os;
  };

  std::istream& operator>>(std::istream& is, Response &resp) {
    YaHTTP::AsyncResponseLoader arl;
    arl.initialize(&resp);
    while(is.good()) {
      char buf[1024];
      is.read(buf, 1024);
      if (is.gcount()>0) { // did we actually read anything
        is.clear();
        if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed
      }
    }
    // throw unless ready
    if (arl.ready() == false)
      throw ParseError("Was not able to extract a valid Response from stream");
    arl.finalize();
    return is;
  };

  std::ostream& operator<<(std::ostream& os, const Request &req) {
    req.write(os);
    return os;
  };

  std::istream& operator>>(std::istream& is, Request &req) {
    YaHTTP::AsyncRequestLoader arl;
    arl.initialize(&req);
    while(is.good()) {
      char buf[1024];
      is.read(buf, 1024);
      if (is.gcount()) { // did we actually read anything
        is.clear();
        if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed
      }
    }
    if (arl.ready() == false)
      throw ParseError("Was not able to extract a valid Request from stream");
    arl.finalize();
    return is;
  };
};
<|endoftext|>


<commit_before>#include "connection.hpp"

#include <sstream>
#include <string>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>

#include <boost/asio/read_until.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/write.hpp>

#include <boost/lexical_cast.hpp>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

//using namespace metaSMT;
//using namespace metaSMT::logic;
//using namespace metaSMT::logic::QF_BV;
//using namespace metaSMT::solver;

Connection::Connection(socket_ptr socket) :
    sock(socket)
{
}

template<typename Context, typename Bitvectors>
typename Context::result_type create_assertion(Context& ctx, const Bitvectors& bitvectors, const boost::property_tree::ptree& pt)
{
    std::string op = pt.get<std::string>("op");

    if (op == "variable")
    {
        return evaluate(ctx, bitvectors.find(pt.get<std::string>("name"))->second);
    }
    else if (op == "integer")
    {
        return evaluate(ctx, metaSMT::logic::QF_BV::bvuint(pt.get<unsigned>("value"), pt.get<unsigned>("width")));
    }
    else if (op == "=")
    {
        typename Context::result_type lhs = create_assertion(ctx, bitvectors, pt.get_child("lhs"));
        typename Context::result_type rhs = create_assertion(ctx, bitvectors, pt.get_child("rhs"));

        return evaluate(ctx, metaSMT::logic::equal(lhs, rhs));
    }
    else
    {
        std::cout << "implement me: " << pt.get<std::string>("op") << std::endl;
    }
}

void Connection::start()
{
    metaSMT::DirectSolver_Context<metaSMT::solver::Z3_Backend> solver;
    std::map<std::string, metaSMT::logic::predicate> predicates;
    std::map<std::string, metaSMT::logic::QF_BV::bitvector> bitvectors;

    try
    {
        for (;;)
        {
            std::string ret;

            boost::system::error_code error;
            boost::asio::streambuf b;
            size_t length = read_until(*sock, b, '\n', error);
            if (error == boost::asio::error::eof) break;
            else if (error) throw boost::system::system_error(error);

            std::istream is(&b);
            std::string s;
            std::getline(is, s);
            if (boost::starts_with(s, "new_variable"))
            {
                std::vector<std::string> split;
                boost::split(split, s, boost::algorithm::is_any_of(" "));

                if (split.size() != 2u) {
                    ret = "Not enough arguments\n";
                } else {
                    predicates.insert(std::make_pair(split[1], metaSMT::logic::new_variable()));
                    std::cout << "[INFO] Added predicate " << split[1] << std::endl;
                    ret = "OK\n";
                }
            }
            else if (boost::starts_with(s, "new_bitvector"))
            {
                std::vector<std::string> split;
                boost::split(split, s, boost::algorithm::is_any_of(" "));

                if (split.size() != 3u) {
                    ret = "Not enough arguments\n";
                } else {
                    bitvectors.insert(std::make_pair(split[1], metaSMT::logic::QF_BV::new_bitvector(boost::lexical_cast<unsigned>(split[2]))));
                    std::cout << "[INFO] Added bit-vector " << split[1] << " of size " << split[2] << std::endl;
                    ret = "OK\n";
                }
            }
            else if (boost::starts_with(s, "assertion"))
            {
                std::cout << s.substr(10u) << std::endl;

                // trim s such that it only contains the json string
                boost::property_tree::ptree pt;

                std::istringstream in(s.substr(10u));
                boost::property_tree::json_parser::read_json(in, pt);

                assertion(solver, create_assertion(solver, bitvectors, pt));

                ret = "OK\n";
            }
            else if (boost::starts_with(s, "solve"))
            {
                bool result = solve(solver);
                ret = result ? "SAT\n" : "UNSAT\n";
            }
            else if (boost::starts_with(s, "modelvalue"))
            {
                std::vector<std::string> split;
                boost::split(split, s, boost::algorithm::is_any_of(" "));

                if (split.size() != 2u) {
                    ret = "Not enough arguments\n";
                } else {
                    unsigned value = read_value(solver, bitvectors[split[1]]);
                    ret = boost::lexical_cast<std::string>(value) + "\n";
                }
            }
            else
            {
                std::cerr << "I do not understand: " << s;
                ret = "FAIL\n";
            }

            boost::asio::write(*sock, boost::asio::buffer(ret, ret.size()));
        }
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception in thread: " << e.what() << std::endl;
    }
}
<commit_msg>metaSMT-server: remove local variables (solver,bitvectors,etc.) in favor of object variables<commit_after>#include "connection.hpp"

#include <sstream>
#include <string>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>

#include <boost/asio/read_until.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/write.hpp>

#include <boost/lexical_cast.hpp>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

//using namespace metaSMT;
//using namespace metaSMT::logic;
//using namespace metaSMT::logic::QF_BV;
//using namespace metaSMT::solver;

Connection::Connection(socket_ptr socket) :
    sock(socket)
{
}

template<typename Context, typename Bitvectors>
typename Context::result_type create_assertion(Context& ctx, const Bitvectors& bitvectors, const boost::property_tree::ptree& pt)
{
    std::string op = pt.get<std::string>("op");

    if (op == "variable")
    {
        return evaluate(ctx, bitvectors.find(pt.get<std::string>("name"))->second);
    }
    else if (op == "integer")
    {
        return evaluate(ctx, metaSMT::logic::QF_BV::bvuint(pt.get<unsigned>("value"), pt.get<unsigned>("width")));
    }
    else if (op == "=")
    {
        typename Context::result_type lhs = create_assertion(ctx, bitvectors, pt.get_child("lhs"));
        typename Context::result_type rhs = create_assertion(ctx, bitvectors, pt.get_child("rhs"));

        return evaluate(ctx, metaSMT::logic::equal(lhs, rhs));
    }
    else
    {
        std::cout << "implement me: " << pt.get<std::string>("op") << std::endl;
    }
}

void Connection::start()
{
    try
    {
        for (;;)
        {
            std::string ret;

            boost::system::error_code error;
            boost::asio::streambuf b;
            size_t length = read_until(*sock, b, '\n', error);
            if (error == boost::asio::error::eof) break;
            else if (error) throw boost::system::system_error(error);

            std::istream is(&b);
            std::string s;
            std::getline(is, s);
            if (boost::starts_with(s, "new_variable"))
            {
                std::vector<std::string> split;
                boost::split(split, s, boost::algorithm::is_any_of(" "));

                if (split.size() != 2u) {
                    ret = "Not enough arguments\n";
                } else {
                    predicates.insert(std::make_pair(split[1], metaSMT::logic::new_variable()));
                    std::cout << "[INFO] Added predicate " << split[1] << std::endl;
                    ret = "OK\n";
                }
            }
            else if (boost::starts_with(s, "new_bitvector"))
            {
                std::vector<std::string> split;
                boost::split(split, s, boost::algorithm::is_any_of(" "));

                if (split.size() != 3u) {
                    ret = "Not enough arguments\n";
                } else {
                    bitvectors.insert(std::make_pair(split[1], metaSMT::logic::QF_BV::new_bitvector(boost::lexical_cast<unsigned>(split[2]))));
                    std::cout << "[INFO] Added bit-vector " << split[1] << " of size " << split[2] << std::endl;
                    ret = "OK\n";
                }
            }
            else if (boost::starts_with(s, "assertion"))
            {
                std::cout << s.substr(10u) << std::endl;

                // trim s such that it only contains the json string
                boost::property_tree::ptree pt;

                std::istringstream in(s.substr(10u));
                boost::property_tree::json_parser::read_json(in, pt);

                assertion(solver, create_assertion(solver, bitvectors, pt));

                ret = "OK\n";
            }
            else if (boost::starts_with(s, "solve"))
            {
                bool result = solve(solver);
                ret = result ? "SAT\n" : "UNSAT\n";
            }
            else if (boost::starts_with(s, "modelvalue"))
            {
                std::vector<std::string> split;
                boost::split(split, s, boost::algorithm::is_any_of(" "));

                if (split.size() != 2u) {
                    ret = "Not enough arguments\n";
                } else {
                    unsigned value = read_value(solver, bitvectors[split[1]]);
                    ret = boost::lexical_cast<std::string>(value) + "\n";
                }
            }
            else
            {
                std::cerr << "I do not understand: " << s;
                ret = "FAIL\n";
            }

            boost::asio::write(*sock, boost::asio::buffer(ret, ret.size()));
        }
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception in thread: " << e.what() << std::endl;
    }
}
<|endoftext|>


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

#include "net/url_request/url_request_job_manager.h"

#include "build/build_config.h"
#include "base/string_util.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_about_job.h"
#include "net/url_request/url_request_error_job.h"
#if defined(OS_WIN)
#include "net/url_request/url_request_file_job.h"
#include "net/url_request/url_request_ftp_job.h"
#else
// TODO(playmobil): Implement on non-windows platforms.
#endif
#include "net/url_request/url_request_http_job.h"
#include "net/url_request/url_request_view_cache_job.h"

// The built-in set of protocol factories
namespace {

struct SchemeToFactory {
  const char* scheme;
  URLRequest::ProtocolFactory* factory;
};

}  // namespace

static const SchemeToFactory kBuiltinFactories[] = {
  { "http", URLRequestHttpJob::Factory },
  { "https", URLRequestHttpJob::Factory },
#if defined(OS_WIN)
  { "file", URLRequestFileJob::Factory },
  { "ftp", URLRequestFtpJob::Factory },
#else
// TODO(playmobil): Implement on non-windows platforms.
#endif
  { "about", URLRequestAboutJob::Factory },
  { "view-cache", URLRequestViewCacheJob::Factory },
};

URLRequestJobManager::URLRequestJobManager() {
#ifndef NDEBUG
  allowed_thread_ = 0;
  allowed_thread_initialized_ = false;
#endif
}

URLRequestJob* URLRequestJobManager::CreateJob(URLRequest* request) const {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  // If we are given an invalid URL, then don't even try to inspect the scheme.
  if (!request->url().is_valid())
    return new URLRequestErrorJob(request, net::ERR_INVALID_URL);

  const std::string& scheme = request->url().scheme();  // already lowercase

  // We do this here to avoid asking interceptors about unsupported schemes.
  if (!SupportsScheme(scheme))
    return new URLRequestErrorJob(request, net::ERR_UNKNOWN_URL_SCHEME);

  // THREAD-SAFETY NOTICE:
  //   We do not need to acquire the lock here since we are only reading our
  //   data structures.  They should only be modified on the current thread.

  // See if the request should be intercepted.
  if (!(request->load_flags() & net::LOAD_DISABLE_INTERCEPT)) {
    InterceptorList::const_iterator i;
    for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
      URLRequestJob* job = (*i)->MaybeIntercept(request);
      if (job)
        return job;
    }
  }

  // See if the request should be handled by a registered protocol factory.
  // If the registered factory returns null, then we want to fall-back to the
  // built-in protocol factory.
  FactoryMap::const_iterator i = factories_.find(scheme);
  if (i != factories_.end()) {
    URLRequestJob* job = i->second(request, scheme);
    if (job)
      return job;
  }

  // See if the request should be handled by a built-in protocol factory.
  for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) {
    if (scheme == kBuiltinFactories[i].scheme) {
      URLRequestJob* job = (kBuiltinFactories[i].factory)(request, scheme);
      DCHECK(job);  // The built-in factories are not expected to fail!
      return job;
    }
  }

  // If we reached here, then it means that a registered protocol factory
  // wasn't interested in handling the URL.  That is fairly unexpected, and we
  // don't know have a specific error to report here :-(
  return new URLRequestErrorJob(request, net::ERR_FAILED);
}

bool URLRequestJobManager::SupportsScheme(const std::string& scheme) const {
  // The set of registered factories may change on another thread.
  {
    AutoLock locked(lock_);
    if (factories_.find(scheme) != factories_.end())
      return true;
  }

  for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i)
    if (LowerCaseEqualsASCII(scheme, kBuiltinFactories[i].scheme))
      return true;

  return false;
}

URLRequest::ProtocolFactory* URLRequestJobManager::RegisterProtocolFactory(
    const std::string& scheme,
    URLRequest::ProtocolFactory* factory) {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  AutoLock locked(lock_);

  URLRequest::ProtocolFactory* old_factory;
  FactoryMap::iterator i = factories_.find(scheme);
  if (i != factories_.end()) {
    old_factory = i->second;
  } else {
    old_factory = NULL;
  }
  if (factory) {
    factories_[scheme] = factory;
  } else if (i != factories_.end()) {  // uninstall any old one
    factories_.erase(i);
  }
  return old_factory;
}

void URLRequestJobManager::RegisterRequestInterceptor(
    URLRequest::Interceptor* interceptor) {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  AutoLock locked(lock_);

  DCHECK(std::find(interceptors_.begin(), interceptors_.end(), interceptor) ==
         interceptors_.end());
  interceptors_.push_back(interceptor);
}

void URLRequestJobManager::UnregisterRequestInterceptor(
    URLRequest::Interceptor* interceptor) {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  AutoLock locked(lock_);

  InterceptorList::iterator i =
      std::find(interceptors_.begin(), interceptors_.end(), interceptor);
  DCHECK(i != interceptors_.end());
  interceptors_.erase(i);
}

<commit_msg>fix build bustage due to missing header<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/url_request/url_request_job_manager.h"

#include <algorithm>

#include "build/build_config.h"
#include "base/string_util.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_about_job.h"
#include "net/url_request/url_request_error_job.h"
#if defined(OS_WIN)
#include "net/url_request/url_request_file_job.h"
#include "net/url_request/url_request_ftp_job.h"
#else
// TODO(playmobil): Implement on non-windows platforms.
#endif
#include "net/url_request/url_request_http_job.h"
#include "net/url_request/url_request_view_cache_job.h"

// The built-in set of protocol factories
namespace {

struct SchemeToFactory {
  const char* scheme;
  URLRequest::ProtocolFactory* factory;
};

}  // namespace

static const SchemeToFactory kBuiltinFactories[] = {
  { "http", URLRequestHttpJob::Factory },
  { "https", URLRequestHttpJob::Factory },
#if defined(OS_WIN)
  { "file", URLRequestFileJob::Factory },
  { "ftp", URLRequestFtpJob::Factory },
#else
// TODO(playmobil): Implement on non-windows platforms.
#endif
  { "about", URLRequestAboutJob::Factory },
  { "view-cache", URLRequestViewCacheJob::Factory },
};

URLRequestJobManager::URLRequestJobManager() {
#ifndef NDEBUG
  allowed_thread_ = 0;
  allowed_thread_initialized_ = false;
#endif
}

URLRequestJob* URLRequestJobManager::CreateJob(URLRequest* request) const {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  // If we are given an invalid URL, then don't even try to inspect the scheme.
  if (!request->url().is_valid())
    return new URLRequestErrorJob(request, net::ERR_INVALID_URL);

  const std::string& scheme = request->url().scheme();  // already lowercase

  // We do this here to avoid asking interceptors about unsupported schemes.
  if (!SupportsScheme(scheme))
    return new URLRequestErrorJob(request, net::ERR_UNKNOWN_URL_SCHEME);

  // THREAD-SAFETY NOTICE:
  //   We do not need to acquire the lock here since we are only reading our
  //   data structures.  They should only be modified on the current thread.

  // See if the request should be intercepted.
  if (!(request->load_flags() & net::LOAD_DISABLE_INTERCEPT)) {
    InterceptorList::const_iterator i;
    for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
      URLRequestJob* job = (*i)->MaybeIntercept(request);
      if (job)
        return job;
    }
  }

  // See if the request should be handled by a registered protocol factory.
  // If the registered factory returns null, then we want to fall-back to the
  // built-in protocol factory.
  FactoryMap::const_iterator i = factories_.find(scheme);
  if (i != factories_.end()) {
    URLRequestJob* job = i->second(request, scheme);
    if (job)
      return job;
  }

  // See if the request should be handled by a built-in protocol factory.
  for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) {
    if (scheme == kBuiltinFactories[i].scheme) {
      URLRequestJob* job = (kBuiltinFactories[i].factory)(request, scheme);
      DCHECK(job);  // The built-in factories are not expected to fail!
      return job;
    }
  }

  // If we reached here, then it means that a registered protocol factory
  // wasn't interested in handling the URL.  That is fairly unexpected, and we
  // don't know have a specific error to report here :-(
  return new URLRequestErrorJob(request, net::ERR_FAILED);
}

bool URLRequestJobManager::SupportsScheme(const std::string& scheme) const {
  // The set of registered factories may change on another thread.
  {
    AutoLock locked(lock_);
    if (factories_.find(scheme) != factories_.end())
      return true;
  }

  for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i)
    if (LowerCaseEqualsASCII(scheme, kBuiltinFactories[i].scheme))
      return true;

  return false;
}

URLRequest::ProtocolFactory* URLRequestJobManager::RegisterProtocolFactory(
    const std::string& scheme,
    URLRequest::ProtocolFactory* factory) {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  AutoLock locked(lock_);

  URLRequest::ProtocolFactory* old_factory;
  FactoryMap::iterator i = factories_.find(scheme);
  if (i != factories_.end()) {
    old_factory = i->second;
  } else {
    old_factory = NULL;
  }
  if (factory) {
    factories_[scheme] = factory;
  } else if (i != factories_.end()) {  // uninstall any old one
    factories_.erase(i);
  }
  return old_factory;
}

void URLRequestJobManager::RegisterRequestInterceptor(
    URLRequest::Interceptor* interceptor) {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  AutoLock locked(lock_);

  DCHECK(std::find(interceptors_.begin(), interceptors_.end(), interceptor) ==
         interceptors_.end());
  interceptors_.push_back(interceptor);
}

void URLRequestJobManager::UnregisterRequestInterceptor(
    URLRequest::Interceptor* interceptor) {
#ifndef NDEBUG
  DCHECK(IsAllowedThread());
#endif

  AutoLock locked(lock_);

  InterceptorList::iterator i =
      std::find(interceptors_.begin(), interceptors_.end(), interceptor);
  DCHECK(i != interceptors_.end());
  interceptors_.erase(i);
}

<|endoftext|>


<commit_before>class Solution {
    struct Info {
        int max_first=std::numeric_limits<int>::min();
        int max_second=std::numeric_limits<int>::min();
        int max_sum=std::numeric_limits<int>::min();
    };
public:
    // For each index i, we will store the following.
    // 1. The sum and end index of the longest subarray of length firstLen so far.
    // 2. The sum and end index of the longest subarray of length secondLen so far.
    // (Note that 1 and 2 could overlap in this, we will handle that in the recurrence).
    // 3. The max sum of 2 non-overlapping subarrays of firstLen and secondLen.
    // Let us call this struct Info.
    //
    // When a new index i is added to existing i-1 elements, we have 3 cases:
    // 1. The max sum remains unchanged, because the added element in inconsequential.
    // 2. The max sum changes, because the added index forms a new firstLen sized subarray ending at i.
    // 3. The max sum changes, because the added index forms a new secondLen sized subarray ending at i.
    // We choose the max of these 3 choices.
    //
    // O(n) time, O(n) space.
    int maxSumTwoNoOverlap(vector<int>& nums, int firstLen, int secondLen) {
        if (firstLen + secondLen > nums.size()) return 0;
        // make it so firstlen always smaller than secondlen
        if (firstLen > secondLen) {std::swap(firstLen, secondLen);}

        vector<Info> cache(nums.size(), Info());

        // Base cases.
        int first_sum=0, second_sum=0;          // stores first and second len sums.
        int max_first_sum=0, max_second_sum=0;  // stores maxes so far for the same
        for (int i=0; i<(firstLen+secondLen)-1; i++) {
            first_sum += nums[i];
            first_sum -= (i < firstLen ? 0 : nums[i-firstLen]);
            if (i >= firstLen-1) {
                if (first_sum > max_first_sum) { max_first_sum = first_sum;}
                cache[i].max_first = max_first_sum;
            }

            second_sum += nums[i];
            second_sum -= (i < secondLen ? 0 : nums[i-secondLen]);
            if (i >= secondLen-1) {
                if (second_sum > max_second_sum) { max_second_sum = second_sum;}
                cache[i].max_second = max_second_sum;
            }
        }

        // DP.
        // first_sum and second_sum carry over.
        for (int i=firstLen+secondLen-1; i<nums.size(); i++) {
            first_sum  += nums[i] - nums[i-firstLen];
            if (first_sum > max_first_sum) { max_first_sum = first_sum; }

            second_sum += nums[i] - nums[i-secondLen];
            if (second_sum > max_second_sum) { max_second_sum = second_sum; }

            // 1. When the max sum remains unchanged.
            int c1 = cache[i-1].max_sum;

            // 2. When the current firstLen seq ending at i forms part of the solution.
            int first_seq_starts = i-firstLen+1;
            int c2 = cache[first_seq_starts-1].max_second + first_sum;

            // 3. When the current secondLen seq ending at i forms part of the solution.
            int second_seq_starts = i-secondLen+1;
            int c3 = cache[second_seq_starts-1].max_first + second_sum;

            // Update cache;
            cache[i].max_first = max_first_sum;
            cache[i].max_second = max_second_sum;
            cache[i].max_sum = std::max(c1, std::max(c2, c3));
        }

        return cache[nums.size()-1].max_sum;
    }
};
<commit_msg>Minor edit again.<commit_after>class Solution {
    struct Info {
        int max_first=std::numeric_limits<int>::min();
        int max_second=std::numeric_limits<int>::min();
        int max_sum=std::numeric_limits<int>::min();
    };
public:
    // For each index i, we will store the following.
    // 1. The sum of the max subarray of length firstLen so far.
    // 2. The sum of the max subarray of length secondLen so far.
    // (Note that 1 and 2 could overlap in this, we will handle that in the recurrence).
    // 3. The max sum of 2 non-overlapping subarrays of firstLen and secondLen.
    // Let us call this struct Info.
    //
    // When a new index i is added to existing i-1 elements, we have 3 cases:
    // 1. The max sum remains unchanged, because the added element in inconsequential.
    // 2. The max sum changes, because the added index forms a new firstLen sized subarray ending at i.
    // 3. The max sum changes, because the added index forms a new secondLen sized subarray ending at i.
    // We choose the max of these 3 choices.
    //
    // O(n) time, O(n) space.
    int maxSumTwoNoOverlap(vector<int>& nums, int firstLen, int secondLen) {
        if (firstLen + secondLen > nums.size()) return 0;
        // make it so firstlen always smaller than secondlen
        if (firstLen > secondLen) {std::swap(firstLen, secondLen);}

        vector<Info> cache(nums.size(), Info());

        // Base cases.
        int first_sum=0, second_sum=0;          // stores first and second len sums.
        int max_first_sum=0, max_second_sum=0;  // stores maxes so far for the same
        for (int i=0; i<(firstLen+secondLen)-1; i++) {
            first_sum += nums[i];
            first_sum -= (i < firstLen ? 0 : nums[i-firstLen]);
            if (i >= firstLen-1) {
                if (first_sum > max_first_sum) { max_first_sum = first_sum;}
                cache[i].max_first = max_first_sum;
            }

            second_sum += nums[i];
            second_sum -= (i < secondLen ? 0 : nums[i-secondLen]);
            if (i >= secondLen-1) {
                if (second_sum > max_second_sum) { max_second_sum = second_sum;}
                cache[i].max_second = max_second_sum;
            }
        }

        // DP.
        // first_sum and second_sum carry over.
        for (int i=firstLen+secondLen-1; i<nums.size(); i++) {
            first_sum  += nums[i] - nums[i-firstLen];
            if (first_sum > max_first_sum) { max_first_sum = first_sum; }

            second_sum += nums[i] - nums[i-secondLen];
            if (second_sum > max_second_sum) { max_second_sum = second_sum; }

            // 1. When the max sum remains unchanged.
            int c1 = cache[i-1].max_sum;

            // 2. When the current firstLen seq ending at i forms part of the solution.
            int first_seq_starts = i-firstLen+1;
            int c2 = cache[first_seq_starts-1].max_second + first_sum;

            // 3. When the current secondLen seq ending at i forms part of the solution.
            int second_seq_starts = i-secondLen+1;
            int c3 = cache[second_seq_starts-1].max_first + second_sum;

            // Update cache;
            cache[i].max_first = max_first_sum;
            cache[i].max_second = max_second_sum;
            cache[i].max_sum = std::max(c1, std::max(c2, c3));
        }

        return cache[nums.size()-1].max_sum;
    }
};
<|endoftext|>


<commit_before>//
// Fence3d.cpp
//
// Creates fence geometry, drapes on a terrain
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "Light.h"
#include "Terrain.h"
#include "Fence3d.h"

// statics
vtMaterialArray *vtFence3d::s_pFenceMats;
float vtFence3d::s_fFenceScale;	// fence size is exaggerated by this amount

vtFence3d::vtFence3d() : vtFence()
{
	Init();
}

vtFence3d::vtFence3d(FenceType type, float fHeight, float fSpacing) : vtFence(type, fHeight, fSpacing)
{
	Init();
}

void vtFence3d::Init()
{
	m_bBuilt = false;
	m_pFenceGeom = NULL;
}

int vtFence3d::m_mi_woodpost;
int vtFence3d::m_mi_wire;
int vtFence3d::m_mi_chainlink;
int vtFence3d::m_mi_metalpost;
int vtFence3d::m_mi_hedgerow;
int vtFence3d::m_mi_drystone;
int vtFence3d::m_mi_privet;
int vtFence3d::m_mi_stone;
int vtFence3d::m_mi_beech;

void vtFence3d::CreateMaterials()
{
	s_pFenceMats = new vtMaterialArray();

	// create wirefence post textured material (0)
	vtString fname;

	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/fencepost_64.bmp");
	m_mi_woodpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,
		TERRAIN_AMBIENT,
		TERRAIN_DIFFUSE,
		1.0f,		// alpha
		TERRAIN_EMISSIVE);

	// add wire material (1)
	m_mi_wire = s_pFenceMats->AddRGBMaterial(RGBf(0.0f, 0.0f, 0.0f), // diffuse
		RGBf(0.5f, 0.5f, 0.5f),	// ambient
		false, true, false,		// culling, lighting, wireframe
		0.6f);					// alpha

	// chainlink material(2)
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/chain128-4.png");
	m_mi_chainlink = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		1.0f,	// ambient
		0.0f,	// diffuse
		1.0f,	// alpha
		TERRAIN_EMISSIVE);

	// create chainfence post textured material (3)
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/chainpost32.bmp");
	m_mi_metalpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create hedgerow textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/hedgerow256.png");
	m_mi_hedgerow = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create drystone textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/drystone256.png");
	m_mi_drystone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create privet textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/privet256.png");
	m_mi_privet = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create stone textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/stone256.png");
	m_mi_stone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create beech textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/beech256.png");
	m_mi_beech = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);
}

void vtFence3d::AddFencepost(FPoint3 &p1, int iMatIdx)
{
	// create fencepost block
	vtMesh *pPostMesh = new vtMesh(GL_TRIANGLE_FAN, VT_Normals | VT_TexCoords, 20);

	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	pPostMesh->CreateOptimizedBlock(PostSizeScaled );

	// scoot over and upwards to put it above ground
	FMatrix4 t;
	t.Identity();
	t.Translate(p1);
	pPostMesh->TransformVertices(t);

	m_pFenceGeom->AddMesh(pPostMesh, iMatIdx);
}

void vtFence3d::AddFenceMeshes(vtHeightField *pHeightField)
{
	Array<DPoint2> posts;
	DPoint2 diff, dp;
	int i, j, nposts;

	int numfencepts = m_pFencePts.GetSize();
	float fCurrentSpacing = m_fSpacing * s_fFenceScale;
	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	float fFenceHeightScaled = m_fHeight * s_fFenceScale;

	// first determine where the fence posts go, for this whole array
	// of fences
	for (i = 0; i < numfencepts; i++)
	{
		if (i == numfencepts-1)
		{
			posts.Append(m_pFencePts[i]);
			continue;
		}
		// get start and end group points for this section
		DPoint2 utm1 = m_pFencePts[i];
		DPoint2 utm2 = m_pFencePts[i+1];

		diff = utm2 - utm1;
		double distance = diff.Length();
		int segments = (int) (distance / fCurrentSpacing);
		if (segments < 1) segments = 1;
		DPoint2 diff_per_segment = diff / segments;

		for (j = 0; j < segments; j++)
		{
			dp = utm1 + (diff_per_segment * j);
			posts.Append(dp);
		}
	}

	// convert post positions to world-coordinate ground locations
	nposts = posts.GetSize();

	FPoint3 pout;
	FLine3 p3;
	p3.SetSize(nposts);
	for (i = 0; i < nposts; i++)
	{
		dp = posts[i];
		pHeightField->ConvertEarthToSurfacePoint(dp.x, dp.y, pout);

		if (i > 0 && i < nposts-1)
		{
			// randomly offset by up to 4% of fence spacing, for "realism"
			pout.x += random_offset(0.04f * fCurrentSpacing);
			pout.z += random_offset(0.04f * fCurrentSpacing);
		}
		p3[i] = pout;
	}

	if (m_FenceType == FT_WIRE)
	{
		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_woodpost);

		// and the 3 wires
		if (nposts > 1)
		{
			float wire_height[3] = { 0.42f, 0.66f, 0.91f };

			vtMesh *pWireMesh = new vtMesh(GL_LINE_STRIP, 0, nposts);
			int vidx = 0;
			for (j = 0; j < 3; j++)
			{
				int start = vidx;
				for (i = 0; i < nposts; i++)
				{
					pWireMesh->AddVertex(p3[i] + FPoint3(0, (PostSizeScaled.y * wire_height[j]), 0));
					vidx++;
				}
				pWireMesh->AddStrip2(nposts, start);
			}
			m_pFenceGeom->AddMesh(pWireMesh, m_mi_wire);
		}
	}

	if (m_FenceType == FT_CHAINLINK)
	{
		float u = 0.0f;
		float fence_height_meters = m_PostSize.y;
		float v_top = fence_height_meters * 2.0f;

		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_metalpost);

		if (nposts > 1)
		{
			vtMesh *pMesh = new vtMesh(GL_TRIANGLE_STRIP, VT_Normals | VT_TexCoords, nposts*2);
			int vidx = 0;
			for (i = 0; i < nposts; i++)
			{
				pMesh->SetVtxPUV(vidx++, p3[i], u, 0.0);
				pMesh->SetVtxPUV(vidx++, p3[i] + FPoint3(0, PostSizeScaled.y, 0), u, v_top);

				if (i < nposts+1)
				{
					// increment u based on the length of each fence segment
					float length = (posts[i+1] - posts[i]).Length();
					u += ((length / s_fFenceScale) * 2.0f);
				}
			}
			pMesh->AddStrip2(nposts * 2, 0);
			m_pFenceGeom->AddMesh(pMesh, m_mi_chainlink);
		}
	}
}

void vtFence3d::DestroyGeometry()
{
	// Destroy the meshes so they can be re-made
	while (m_pFenceGeom->GetNumMeshes())
	{
		vtMesh *pMesh = m_pFenceGeom->GetMesh(0);
		m_pFenceGeom->RemoveMesh(pMesh);
	}

	m_bBuilt = false;
}

/////////////////////////////////////
// Implement vtStructure3d methods

/**
 * Build (or rebuild) the geometry for a fence.
 */
bool vtFence3d::CreateNode(vtHeightField *hf, const vtTagArray &options)
{
	if (!m_pFenceGeom)
	{
		if (s_pFenceMats == NULL)
			CreateMaterials();

		m_pFenceGeom = new vtGeom;
		m_pFenceGeom->SetName2("Fence");
		m_pFenceGeom->SetMaterials(s_pFenceMats);
	}

	if (m_bBuilt)
		DestroyGeometry();

	// create surface and shape
	AddFenceMeshes(hf);

	m_bBuilt = true;
	return true;
}

vtGeom *vtFence3d::GetGeom()
{
	return m_pFenceGeom;
}

void vtFence3d::DeleteNode()
{
	if (m_pFenceGeom)
	{
		DestroyGeometry();
		delete m_pFenceGeom;
		m_pFenceGeom = NULL;
	}
}

<commit_msg>more of Roger James's fence code<commit_after>//
// Fence3d.cpp
//
// Creates fence geometry, drapes on a terrain
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "Light.h"
#include "Terrain.h"
#include "Fence3d.h"

// statics
vtMaterialArray *vtFence3d::s_pFenceMats;
float vtFence3d::s_fFenceScale;	// fence size is exaggerated by this amount

vtFence3d::vtFence3d() : vtFence()
{
	Init();
}

vtFence3d::vtFence3d(FenceType type, float fHeight, float fSpacing) : vtFence(type, fHeight, fSpacing)
{
	Init();
}

void vtFence3d::Init()
{
	m_bBuilt = false;
	m_pFenceGeom = NULL;
}

int vtFence3d::m_mi_woodpost;
int vtFence3d::m_mi_wire;
int vtFence3d::m_mi_chainlink;
int vtFence3d::m_mi_metalpost;
int vtFence3d::m_mi_hedgerow;
int vtFence3d::m_mi_drystone;
int vtFence3d::m_mi_privet;
int vtFence3d::m_mi_stone;
int vtFence3d::m_mi_beech;

void vtFence3d::CreateMaterials()
{
	s_pFenceMats = new vtMaterialArray();

	// create wirefence post textured material (0)
	vtString fname;

	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/fencepost_64.bmp");
	m_mi_woodpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,
		TERRAIN_AMBIENT,
		TERRAIN_DIFFUSE,
		1.0f,		// alpha
		TERRAIN_EMISSIVE);

	// add wire material (1)
	m_mi_wire = s_pFenceMats->AddRGBMaterial(RGBf(0.0f, 0.0f, 0.0f), // diffuse
		RGBf(0.5f, 0.5f, 0.5f),	// ambient
		false, true, false,		// culling, lighting, wireframe
		0.6f);					// alpha

	// chainlink material(2)
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/chain128-4.png");
	m_mi_chainlink = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		1.0f,	// ambient
		0.0f,	// diffuse
		1.0f,	// alpha
		TERRAIN_EMISSIVE);

	// create chainfence post textured material (3)
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/chainpost32.bmp");
	m_mi_metalpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create hedgerow textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/hedgerow256.png");
	m_mi_hedgerow = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create drystone textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/drystone256.png");
	m_mi_drystone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create privet textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/privet256.png");
	m_mi_privet = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create stone textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/stone256.png");
	m_mi_stone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create beech textured material
	fname = FindFileOnPaths(vtTerrain::m_DataPaths, "Culture/beech256.png");
	m_mi_beech = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);
}

void vtFence3d::AddFencepost(FPoint3 &p1, int iMatIdx)
{
	// create fencepost block
	vtMesh *pPostMesh = new vtMesh(GL_TRIANGLE_FAN, VT_Normals | VT_TexCoords, 20);

	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	pPostMesh->CreateOptimizedBlock(PostSizeScaled );

	// scoot over and upwards to put it above ground
	FMatrix4 t;
	t.Identity();
	t.Translate(p1);
	pPostMesh->TransformVertices(t);

	m_pFenceGeom->AddMesh(pPostMesh, iMatIdx);
}

void vtFence3d::AddFenceMeshes(vtHeightField *pHeightField)
{
	Array<DPoint2> posts;
	DPoint2 diff, dp;
	int i, j, nposts;

	int numfencepts = m_pFencePts.GetSize();
	float fCurrentSpacing = m_fSpacing * s_fFenceScale;
	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	float fFenceHeightScaled = m_fHeight * s_fFenceScale;

	if ((FT_WIRE == m_FenceType) || (FT_CHAINLINK == m_FenceType))
	{
	// first determine where the fence posts go, for this whole array
	// of fences
	for (i = 0; i < numfencepts; i++)
	{
		if (i == numfencepts-1)
		{
			posts.Append(m_pFencePts[i]);
			continue;
		}
		// get start and end group points for this section
		DPoint2 utm1 = m_pFencePts[i];
		DPoint2 utm2 = m_pFencePts[i+1];

		diff = utm2 - utm1;
		double distance = diff.Length();
		int segments = (int) (distance / fCurrentSpacing);
		if (segments < 1) segments = 1;
		DPoint2 diff_per_segment = diff / segments;

		for (j = 0; j < segments; j++)
		{
			dp = utm1 + (diff_per_segment * j);
			posts.Append(dp);
		}
	}

	// convert post positions to world-coordinate ground locations
	nposts = posts.GetSize();

	FPoint3 pout;
	FLine3 p3;
	p3.SetSize(nposts);
	for (i = 0; i < nposts; i++)
	{
		dp = posts[i];
		pHeightField->ConvertEarthToSurfacePoint(dp.x, dp.y, pout);

		if (i > 0 && i < nposts-1)
		{
			// randomly offset by up to 4% of fence spacing, for "realism"
			pout.x += random_offset(0.04f * fCurrentSpacing);
			pout.z += random_offset(0.04f * fCurrentSpacing);
		}
		p3[i] = pout;
	}

	if (m_FenceType == FT_WIRE)
	{
		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_woodpost);

		// and the 3 wires
		if (nposts > 1)
		{
			float wire_height[3] = { 0.42f, 0.66f, 0.91f };

			vtMesh *pWireMesh = new vtMesh(GL_LINE_STRIP, 0, nposts);
			int vidx = 0;
			for (j = 0; j < 3; j++)
			{
				int start = vidx;
				for (i = 0; i < nposts; i++)
				{
					pWireMesh->AddVertex(p3[i] + FPoint3(0, (PostSizeScaled.y * wire_height[j]), 0));
					vidx++;
				}
				pWireMesh->AddStrip2(nposts, start);
			}
			m_pFenceGeom->AddMesh(pWireMesh, m_mi_wire);
		}
	}

	if (m_FenceType == FT_CHAINLINK)
	{
		float u = 0.0f;
		float fence_height_meters = m_PostSize.y;
		float v_top = fence_height_meters * 2.0f;

		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_metalpost);

		if (nposts > 1)
		{
			vtMesh *pMesh = new vtMesh(GL_TRIANGLE_STRIP, VT_Normals | VT_TexCoords, nposts*2);
			int vidx = 0;
			for (i = 0; i < nposts; i++)
			{
				pMesh->SetVtxPUV(vidx++, p3[i], u, 0.0);
				pMesh->SetVtxPUV(vidx++, p3[i] + FPoint3(0, PostSizeScaled.y, 0), u, v_top);

				if (i < nposts+1)
				{
					// increment u based on the length of each fence segment
					float length = (posts[i+1] - posts[i]).Length();
					u += ((length / s_fFenceScale) * 2.0f);
				}
			}
			pMesh->AddStrip2(nposts * 2, 0);
			m_pFenceGeom->AddMesh(pMesh, m_mi_chainlink);
			}
		}
	}
	else
	{
		// FT_HEDGEROW has no posts
		if (numfencepts > 1)
		{
			float u = 0.0f;
			FPoint3 pout;
			vtMesh *pMesh = new vtMesh(GL_TRIANGLE_STRIP, VT_Normals | VT_TexCoords, numfencepts * 2);
			int vidx = 0;
			for (i = 0; i < numfencepts; i++)
			{
				dp = m_pFencePts[i];
				pHeightField->ConvertEarthToSurfacePoint(dp.x, dp.y, pout);

				pMesh->SetVtxPUV(vidx++, pout, u, 1.0f);
				pMesh->SetVtxPUV(vidx++, pout + FPoint3(0, fFenceHeightScaled, 0), u, 0.0f);

				if (i < (numfencepts - 1))
				{
					// increment u based on the length of each fence segment
					float length = (m_pFencePts[i+1] - dp).Length();
					u += ((length / s_fFenceScale) * 0.5f);
				}
			}
			pMesh->AddStrip2(numfencepts * 2, 0);
			switch(m_FenceType)
			{
				case FT_HEDGEROW:
					m_pFenceGeom->AddMesh(pMesh, m_mi_hedgerow);
					break;
				case FT_DRYSTONE:
					m_pFenceGeom->AddMesh(pMesh, m_mi_drystone);
					break;
				case FT_PRIVET:
					m_pFenceGeom->AddMesh(pMesh, m_mi_privet);
					break;
				case FT_STONE:
					m_pFenceGeom->AddMesh(pMesh, m_mi_stone);
					break;
				case FT_BEECH:
					m_pFenceGeom->AddMesh(pMesh, m_mi_beech);
					break;
			}
		}
	}
}

void vtFence3d::DestroyGeometry()
{
	// Destroy the meshes so they can be re-made
	while (m_pFenceGeom->GetNumMeshes())
	{
		vtMesh *pMesh = m_pFenceGeom->GetMesh(0);
		m_pFenceGeom->RemoveMesh(pMesh);
	}

	m_bBuilt = false;
}

/////////////////////////////////////
// Implement vtStructure3d methods

/**
 * Build (or rebuild) the geometry for a fence.
 */
bool vtFence3d::CreateNode(vtHeightField *hf, const vtTagArray &options)
{
	if (!m_pFenceGeom)
	{
		if (s_pFenceMats == NULL)
			CreateMaterials();

		m_pFenceGeom = new vtGeom;
		m_pFenceGeom->SetName2("Fence");
		m_pFenceGeom->SetMaterials(s_pFenceMats);
	}

	if (m_bBuilt)
		DestroyGeometry();

	// create surface and shape
	AddFenceMeshes(hf);

	m_bBuilt = true;
	return true;
}

vtGeom *vtFence3d::GetGeom()
{
	return m_pFenceGeom;
}

void vtFence3d::DeleteNode()
{
	if (m_pFenceGeom)
	{
		DestroyGeometry();
		delete m_pFenceGeom;
		m_pFenceGeom = NULL;
	}
}

<|endoftext|>


<commit_before>//
// Fence3d.cpp
//
// Creates fence geometry, drapes on a terrain
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "Light.h"
#include "Terrain.h"
#include "Fence3d.h"
#include "TerrainScene.h"

// statics
vtMaterialArray *vtFence3d::s_pFenceMats = NULL;
float vtFence3d::s_fFenceScale;	// fence size is exaggerated by this amount

vtFence3d::vtFence3d() : vtFence()
{
	Init();
}

vtFence3d::vtFence3d(FenceType type, float fHeight, float fSpacing) : vtFence(type, fHeight, fSpacing)
{
	Init();
}

void vtFence3d::Init()
{
	m_bBuilt = false;
	m_pFenceGeom = NULL;
}

int vtFence3d::m_mi_woodpost;
int vtFence3d::m_mi_wire;
int vtFence3d::m_mi_chainlink;
int vtFence3d::m_mi_metalpost;
int vtFence3d::m_mi_hedgerow;
int vtFence3d::m_mi_drystone;
int vtFence3d::m_mi_privet;
int vtFence3d::m_mi_stone;
int vtFence3d::m_mi_beech;

void vtFence3d::CreateMaterials()
{
	s_pFenceMats = new vtMaterialArray();

	// create wirefence post textured material (0)
	vtString fname;

	fname = FindFileOnPaths(vtGetDataPath(), "Culture/fencepost_64.jpg");
	m_mi_woodpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,
		TERRAIN_AMBIENT,
		TERRAIN_DIFFUSE,
		1.0f,		// alpha
		TERRAIN_EMISSIVE);

	// add wire material (1)
	m_mi_wire = s_pFenceMats->AddRGBMaterial(RGBf(0.0f, 0.0f, 0.0f), // diffuse
		RGBf(0.5f, 0.5f, 0.5f),	// ambient
		false, true, false,		// culling, lighting, wireframe
		0.6f);					// alpha

	// chainlink material(2)
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/chain128-4.png");
	m_mi_chainlink = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		1.0f,	// ambient
		0.0f,	// diffuse
		1.0f,	// alpha
		TERRAIN_EMISSIVE);

	// create chainfence post textured material (3)
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/chainpost32.jpg");
	m_mi_metalpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create hedgerow textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/hedgerow256.png");
	m_mi_hedgerow = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create drystone textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/drystone256.png");
	m_mi_drystone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create privet textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/privet256.png");
	m_mi_privet = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create stone textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/stone256.png");
	m_mi_stone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create beech textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/beech256.png");
	m_mi_beech = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);
}

void vtFence3d::AddFencepost(FPoint3 &p1, int iMatIdx)
{
	// create fencepost block
	vtMesh *pPostMesh = new vtMesh(GL_TRIANGLE_FAN, VT_Normals | VT_TexCoords, 20);

	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	pPostMesh->CreateOptimizedBlock(PostSizeScaled );

	// scoot over and upwards to put it above ground
	FMatrix4 t;
	t.Identity();
	t.Translate(p1);
	pPostMesh->TransformVertices(t);

	m_pFenceGeom->AddMesh(pPostMesh, iMatIdx);
	pPostMesh->Release();	// pass ownership
}

void vtFence3d::AddFenceMeshes(vtHeightField3d *pHeightField)
{
	if ((FT_WIRE == m_FenceType) || (FT_CHAINLINK == m_FenceType))
		CreateMeshesWithPosts(pHeightField);
	else
		// FT_HEDGEROW has no posts
		CreateMeshesWithoutPosts(pHeightField);
}

void vtFence3d::CreateMeshesWithPosts(vtHeightField3d *pHeightField)
{
	int i, j;
	int numfencepts = m_pFencePts.GetSize();
	Array<DPoint2> posts;
	DPoint2 diff, dp;
	float fCurrentSpacing = m_fSpacing * s_fFenceScale;
	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	float fFenceHeightScaled = m_fHeight * s_fFenceScale;

	// first determine where the fence posts go, for this whole array
	// of fences
	for (i = 0; i < numfencepts; i++)
	{
		if (i == numfencepts-1)
		{
			posts.Append(m_pFencePts[i]);
			continue;
		}
		// get start and end group points for this section
		DPoint2 utm1 = m_pFencePts[i];
		DPoint2 utm2 = m_pFencePts[i+1];

		diff = utm2 - utm1;
		double distance = diff.Length();
		int segments = (int) (distance / fCurrentSpacing);
		if (segments < 1) segments = 1;
		DPoint2 diff_per_segment = diff / segments;

		for (j = 0; j < segments; j++)
		{
			dp = utm1 + (diff_per_segment * j);
			posts.Append(dp);
		}
	}

	// convert post positions to world-coordinate ground locations
	int nposts = posts.GetSize();

	FPoint3 pout;
	FLine3 p3;
	p3.SetSize(nposts);
	for (i = 0; i < nposts; i++)
	{
		pHeightField->ConvertEarthToSurfacePoint(posts[i], pout);

		if (i > 0 && i < nposts-1)
		{
			// randomly offset by up to 4% of fence spacing, for "realism"
			pout.x += random_offset(0.04f * fCurrentSpacing);
			pout.z += random_offset(0.04f * fCurrentSpacing);
		}
		p3[i] = pout;
	}

	if (m_FenceType == FT_WIRE)
	{
		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_woodpost);

		// and the 3 wires
		if (nposts > 1)
		{
			float wire_height[3] = { 0.42f, 0.66f, 0.91f };

			vtMesh *pWireMesh = new vtMesh(GL_LINE_STRIP, 0, nposts);
			int vidx = 0;
			for (j = 0; j < 3; j++)
			{
				int start = vidx;
				for (i = 0; i < nposts; i++)
				{
					pWireMesh->AddVertex(p3[i] + FPoint3(0, (PostSizeScaled.y * wire_height[j]), 0));
					vidx++;
				}
				pWireMesh->AddStrip2(nposts, start);
			}
			m_pFenceGeom->AddMesh(pWireMesh, m_mi_wire);
			pWireMesh->Release();	// pass ownership
		}
	}

	if (m_FenceType == FT_CHAINLINK)
	{
		float u = 0.0f;
		float fence_height_meters = m_PostSize.y;
		float v_top = fence_height_meters * 2.0f;

		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_metalpost);

		if (nposts > 1)
		{
			vtMesh *pMesh = new vtMesh(GL_TRIANGLE_STRIP, VT_Normals | VT_TexCoords, nposts*2);
			int vidx = 0;
			for (i = 0; i < nposts; i++)
			{
				pMesh->SetVtxPUV(vidx++, p3[i], u, 0.0);
				pMesh->SetVtxPUV(vidx++, p3[i] + FPoint3(0, PostSizeScaled.y, 0), u, v_top);

				if (i < nposts+1)
				{
					// increment u based on the length of each fence segment
					float length = (posts[i+1] - posts[i]).Length();
					u += ((length / s_fFenceScale) * 2.0f);
				}
			}
			pMesh->AddStrip2(nposts * 2, 0);
			m_pFenceGeom->AddMesh(pMesh, m_mi_chainlink);
			pMesh->Release();	// pass ownership
		}
	}
}

void vtFence3d::CreateMeshesWithoutPosts(vtHeightField3d *pHeightField)
{
	int i, numfencepts = m_pFencePts.GetSize();

	// FT_HEDGEROW has no posts
	if (numfencepts < 1)
		return;

	float fFenceHeightScaled = m_fHeight * s_fFenceScale;
	float u = 0.0f;
	FPoint3 pout;
	vtMesh *pMesh = new vtMesh(GL_TRIANGLE_STRIP, VT_Normals | VT_TexCoords, numfencepts * 2);
	int vidx = 0;
	for (i = 0; i < numfencepts; i++)
	{
		DPoint2 dp = m_pFencePts[i];
		pHeightField->ConvertEarthToSurfacePoint(dp.x, dp.y, pout);

		pMesh->SetVtxPUV(vidx++, pout, u, 1.0f);
		pMesh->SetVtxPUV(vidx++, pout + FPoint3(0, fFenceHeightScaled, 0), u, 0.0f);

		if (i < (numfencepts - 1))
		{
			// increment u based on the length of each fence segment
			float length = (m_pFencePts[i+1] - dp).Length();
			u += ((length / s_fFenceScale) * 0.5f);
		}
	}
	pMesh->AddStrip2(numfencepts * 2, 0);
	switch(m_FenceType)
	{
	case FT_HEDGEROW:
		m_pFenceGeom->AddMesh(pMesh, m_mi_hedgerow);
		break;
	case FT_DRYSTONE:
		m_pFenceGeom->AddMesh(pMesh, m_mi_drystone);
		break;
	case FT_PRIVET:
		m_pFenceGeom->AddMesh(pMesh, m_mi_privet);
		break;
	case FT_STONE:
		m_pFenceGeom->AddMesh(pMesh, m_mi_stone);
		break;
	case FT_BEECH:
		m_pFenceGeom->AddMesh(pMesh, m_mi_beech);
		break;
	}
	pMesh->Release();	// pass ownership
}

void vtFence3d::DestroyGeometry()
{
	// Destroy the meshes so they can be re-made
	while (m_pFenceGeom->GetNumMeshes())
	{
		vtMesh *pMesh = m_pFenceGeom->GetMesh(0);
		m_pFenceGeom->RemoveMesh(pMesh);
	}

	m_bBuilt = false;
}

/////////////////////////////////////
// Implement vtStructure3d methods

/**
 * Build (or rebuild) the geometry for a fence.
 */
bool vtFence3d::CreateNode(vtTerrain *pTerr)
{
	if (!m_pFenceGeom)
	{
		bool bFirstTime = false;
		if (s_pFenceMats == NULL)
		{
			bFirstTime = true;
			CreateMaterials();
		}

		m_pFenceGeom = new vtGeom;
		m_pFenceGeom->SetName2("Fence");
		m_pFenceGeom->SetMaterials(s_pFenceMats);

		if (bFirstTime)
			s_pFenceMats->Release();
	}

	if (m_bBuilt)
		DestroyGeometry();

	// create surface and shape
	AddFenceMeshes(pTerr->GetHeightField());

	m_bBuilt = true;
	return true;
}

void vtFence3d::DeleteNode()
{
	if (m_pFenceGeom)
	{
		DestroyGeometry();
		m_pFenceGeom->Release();
		m_pFenceGeom = NULL;
	}
}

<commit_msg>flip UV 0/1, from RJ<commit_after>//
// Fence3d.cpp
//
// Creates fence geometry, drapes on a terrain
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "Light.h"
#include "Terrain.h"
#include "Fence3d.h"
#include "TerrainScene.h"

// statics
vtMaterialArray *vtFence3d::s_pFenceMats = NULL;
float vtFence3d::s_fFenceScale;	// fence size is exaggerated by this amount

vtFence3d::vtFence3d() : vtFence()
{
	Init();
}

vtFence3d::vtFence3d(FenceType type, float fHeight, float fSpacing) : vtFence(type, fHeight, fSpacing)
{
	Init();
}

void vtFence3d::Init()
{
	m_bBuilt = false;
	m_pFenceGeom = NULL;
}

int vtFence3d::m_mi_woodpost;
int vtFence3d::m_mi_wire;
int vtFence3d::m_mi_chainlink;
int vtFence3d::m_mi_metalpost;
int vtFence3d::m_mi_hedgerow;
int vtFence3d::m_mi_drystone;
int vtFence3d::m_mi_privet;
int vtFence3d::m_mi_stone;
int vtFence3d::m_mi_beech;

void vtFence3d::CreateMaterials()
{
	s_pFenceMats = new vtMaterialArray();

	// create wirefence post textured material (0)
	vtString fname;

	fname = FindFileOnPaths(vtGetDataPath(), "Culture/fencepost_64.jpg");
	m_mi_woodpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,
		TERRAIN_AMBIENT,
		TERRAIN_DIFFUSE,
		1.0f,		// alpha
		TERRAIN_EMISSIVE);

	// add wire material (1)
	m_mi_wire = s_pFenceMats->AddRGBMaterial(RGBf(0.0f, 0.0f, 0.0f), // diffuse
		RGBf(0.5f, 0.5f, 0.5f),	// ambient
		false, true, false,		// culling, lighting, wireframe
		0.6f);					// alpha

	// chainlink material(2)
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/chain128-4.png");
	m_mi_chainlink = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		1.0f,	// ambient
		0.0f,	// diffuse
		1.0f,	// alpha
		TERRAIN_EMISSIVE);

	// create chainfence post textured material (3)
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/chainpost32.jpg");
	m_mi_metalpost = s_pFenceMats->AddTextureMaterial2(fname,
		true, true, false, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create hedgerow textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/hedgerow256.png");
	m_mi_hedgerow = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create drystone textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/drystone256.png");
	m_mi_drystone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create privet textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/privet256.png");
	m_mi_privet = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create stone textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/stone256.png");
	m_mi_stone = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);

	// create beech textured material
	fname = FindFileOnPaths(vtGetDataPath(), "Culture/beech256.png");
	m_mi_beech = s_pFenceMats->AddTextureMaterial2(fname,
		false, true, true, false,	// cull, light, transp, add
		TERRAIN_AMBIENT, TERRAIN_DIFFUSE, 1.0f, TERRAIN_EMISSIVE);
}

void vtFence3d::AddFencepost(FPoint3 &p1, int iMatIdx)
{
	// create fencepost block
	vtMesh *pPostMesh = new vtMesh(GL_TRIANGLE_FAN, VT_Normals | VT_TexCoords, 20);

	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	pPostMesh->CreateOptimizedBlock(PostSizeScaled );

	// scoot over and upwards to put it above ground
	FMatrix4 t;
	t.Identity();
	t.Translate(p1);
	pPostMesh->TransformVertices(t);

	m_pFenceGeom->AddMesh(pPostMesh, iMatIdx);
	pPostMesh->Release();	// pass ownership
}

void vtFence3d::AddFenceMeshes(vtHeightField3d *pHeightField)
{
	if ((FT_WIRE == m_FenceType) || (FT_CHAINLINK == m_FenceType))
		CreateMeshesWithPosts(pHeightField);
	else
		// FT_HEDGEROW has no posts
		CreateMeshesWithoutPosts(pHeightField);
}

void vtFence3d::CreateMeshesWithPosts(vtHeightField3d *pHeightField)
{
	int i, j;
	int numfencepts = m_pFencePts.GetSize();
	Array<DPoint2> posts;
	DPoint2 diff, dp;
	float fCurrentSpacing = m_fSpacing * s_fFenceScale;
	FPoint3 PostSizeScaled = m_PostSize * s_fFenceScale;
	float fFenceHeightScaled = m_fHeight * s_fFenceScale;

	// first determine where the fence posts go, for this whole array
	// of fences
	for (i = 0; i < numfencepts; i++)
	{
		if (i == numfencepts-1)
		{
			posts.Append(m_pFencePts[i]);
			continue;
		}
		// get start and end group points for this section
		DPoint2 utm1 = m_pFencePts[i];
		DPoint2 utm2 = m_pFencePts[i+1];

		diff = utm2 - utm1;
		double distance = diff.Length();
		int segments = (int) (distance / fCurrentSpacing);
		if (segments < 1) segments = 1;
		DPoint2 diff_per_segment = diff / segments;

		for (j = 0; j < segments; j++)
		{
			dp = utm1 + (diff_per_segment * j);
			posts.Append(dp);
		}
	}

	// convert post positions to world-coordinate ground locations
	int nposts = posts.GetSize();

	FPoint3 pout;
	FLine3 p3;
	p3.SetSize(nposts);
	for (i = 0; i < nposts; i++)
	{
		pHeightField->ConvertEarthToSurfacePoint(posts[i], pout);

		if (i > 0 && i < nposts-1)
		{
			// randomly offset by up to 4% of fence spacing, for "realism"
			pout.x += random_offset(0.04f * fCurrentSpacing);
			pout.z += random_offset(0.04f * fCurrentSpacing);
		}
		p3[i] = pout;
	}

	if (m_FenceType == FT_WIRE)
	{
		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_woodpost);

		// and the 3 wires
		if (nposts > 1)
		{
			float wire_height[3] = { 0.42f, 0.66f, 0.91f };

			vtMesh *pWireMesh = new vtMesh(GL_LINE_STRIP, 0, nposts);
			int vidx = 0;
			for (j = 0; j < 3; j++)
			{
				int start = vidx;
				for (i = 0; i < nposts; i++)
				{
					pWireMesh->AddVertex(p3[i] + FPoint3(0, (PostSizeScaled.y * wire_height[j]), 0));
					vidx++;
				}
				pWireMesh->AddStrip2(nposts, start);
			}
			m_pFenceGeom->AddMesh(pWireMesh, m_mi_wire);
			pWireMesh->Release();	// pass ownership
		}
	}

	if (m_FenceType == FT_CHAINLINK)
	{
		float u = 0.0f;
		float fence_height_meters = m_PostSize.y;
		float v_top = fence_height_meters * 2.0f;

		// generate the posts
		for (i = 0; i < nposts; i++)
			AddFencepost(p3[i], m_mi_metalpost);

		if (nposts > 1)
		{
			vtMesh *pMesh = new vtMesh(GL_TRIANGLE_STRIP, VT_Normals | VT_TexCoords, nposts*2);
			int vidx = 0;
			for (i = 0; i < nposts; i++)
			{
				pMesh->SetVtxPUV(vidx++, p3[i], u, 0.0);
				pMesh->SetVtxPUV(vidx++, p3[i] + FPoint3(0, PostSizeScaled.y, 0), u, v_top);

				if (i < nposts+1)
				{
					// increment u based on the length of each fence segment
					float length = (posts[i+1] - posts[i]).Length();
					u += ((length / s_fFenceScale) * 2.0f);
				}
			}
			pMesh->AddStrip2(nposts * 2, 0);
			m_pFenceGeom->AddMesh(pMesh, m_mi_chainlink);
			pMesh->Release();	// pass ownership
		}
	}
}

void vtFence3d::CreateMeshesWithoutPosts(vtHeightField3d *pHeightField)
{
	int i, numfencepts = m_pFencePts.GetSize();

	// FT_HEDGEROW has no posts
	if (numfencepts < 1)
		return;

	float fFenceHeightScaled = m_fHeight * s_fFenceScale;
	float u = 0.0f;
	FPoint3 pout;
	vtMesh *pMesh = new vtMesh(GL_TRIANGLE_STRIP, VT_Normals | VT_TexCoords, numfencepts * 2);
	int vidx = 0;
	for (i = 0; i < numfencepts; i++)
	{
		DPoint2 dp = m_pFencePts[i];
		pHeightField->ConvertEarthToSurfacePoint(dp.x, dp.y, pout);

		pMesh->SetVtxPUV(vidx++, pout, u, 0.0f);
		pMesh->SetVtxPUV(vidx++, pout + FPoint3(0, fFenceHeightScaled, 0), u, 1.0f);

		if (i < (numfencepts - 1))
		{
			// increment u based on the length of each fence segment
			float length = (m_pFencePts[i+1] - dp).Length();
			u += ((length / s_fFenceScale) * 0.5f);
		}
	}
	pMesh->AddStrip2(numfencepts * 2, 0);
	switch(m_FenceType)
	{
	case FT_HEDGEROW:
		m_pFenceGeom->AddMesh(pMesh, m_mi_hedgerow);
		break;
	case FT_DRYSTONE:
		m_pFenceGeom->AddMesh(pMesh, m_mi_drystone);
		break;
	case FT_PRIVET:
		m_pFenceGeom->AddMesh(pMesh, m_mi_privet);
		break;
	case FT_STONE:
		m_pFenceGeom->AddMesh(pMesh, m_mi_stone);
		break;
	case FT_BEECH:
		m_pFenceGeom->AddMesh(pMesh, m_mi_beech);
		break;
	}
	pMesh->Release();	// pass ownership
}

void vtFence3d::DestroyGeometry()
{
	// Destroy the meshes so they can be re-made
	while (m_pFenceGeom->GetNumMeshes())
	{
		vtMesh *pMesh = m_pFenceGeom->GetMesh(0);
		m_pFenceGeom->RemoveMesh(pMesh);
	}

	m_bBuilt = false;
}

/////////////////////////////////////
// Implement vtStructure3d methods

/**
 * Build (or rebuild) the geometry for a fence.
 */
bool vtFence3d::CreateNode(vtTerrain *pTerr)
{
	if (!m_pFenceGeom)
	{
		bool bFirstTime = false;
		if (s_pFenceMats == NULL)
		{
			bFirstTime = true;
			CreateMaterials();
		}

		m_pFenceGeom = new vtGeom;
		m_pFenceGeom->SetName2("Fence");
		m_pFenceGeom->SetMaterials(s_pFenceMats);

		if (bFirstTime)
			s_pFenceMats->Release();
	}

	if (m_bBuilt)
		DestroyGeometry();

	// create surface and shape
	AddFenceMeshes(pTerr->GetHeightField());

	m_bBuilt = true;
	return true;
}

void vtFence3d::DeleteNode()
{
	if (m_pFenceGeom)
	{
		DestroyGeometry();
		m_pFenceGeom->Release();
		m_pFenceGeom = NULL;
	}
}

<|endoftext|>


<commit_before>/* gobby - A GTKmm driven libobby client
 * Copyright (C) 2005, 2006 0x539 dev group
 *
 * 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 2 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, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "gselector.hpp"

namespace
{
	inline Glib::IOCondition gcond(net6::io_condition cond)
	{
		Glib::IOCondition g_cond = Glib::IOCondition(0);
		if(cond & net6::IO_INCOMING)
			g_cond |= Glib::IO_IN;
		if(cond & net6::IO_OUTGOING)
			g_cond |= Glib::IO_OUT;
		if(cond & net6::IO_ERROR)
			g_cond |= (Glib::IO_HUP | Glib::IO_NVAL | Glib::IO_ERR);
		return g_cond;
	}

	inline net6::io_condition ncond(Glib::IOCondition cond)
	{
		net6::io_condition n_cond = net6::IO_NONE;
		if(cond & Glib::IO_IN)
			n_cond |= net6::IO_INCOMING;
		if(cond & Glib::IO_OUT)
			n_cond |= net6::IO_OUTGOING;
		if(cond & (Glib::IO_HUP | Glib::IO_NVAL | Glib::IO_ERR) )
			n_cond |= net6::IO_ERROR;
		return n_cond;
	}

	net6::io_condition IO_FLAGS =
		net6::IO_INCOMING | net6::IO_OUTGOING | net6::IO_ERROR;
}

Gobby::GSelector::GSelector():
	m_mutex(new Glib::RecMutex)
{
}

Gobby::GSelector::~GSelector()
{
	// Should already be performed by sigc::trackable...
	for(map_type::iterator it = m_map.begin(); it != m_map.end(); ++ it)
		it->second.io_conn.disconnect();
}

void Gobby::GSelector::add_socket(const net6::socket& sock,
                                  net6::io_condition cond)
{
	SelectedSocket& sel = m_map[&sock];

	sel.sock = &sock;
	sel.cond = cond;

	// Timeout is set in set_timeout
	if( (cond & IO_FLAGS) != net6::IO_NONE)
	{
		net6::socket::socket_type fd = sock.cobj();

		sel.io_chan =
#ifdef _WIN32
			Glib::IOChannel::create_from_win32_socket(fd);
#else
			Glib::IOChannel::create_from_fd(fd);
#endif

		sel.io_conn = Glib::signal_io().connect(
			sigc::bind(
				sigc::mem_fun(*this, &GSelector::on_io),
				&sock
			),
			sel.io_chan,
			gcond(cond)
		);
	}
}

void Gobby::GSelector::modify_socket(map_type::iterator iter,
                                     net6::io_condition cond)
{
	// IO_FLAGS did change
	if( (iter->second.cond & IO_FLAGS) != (cond & IO_FLAGS) )
	{
		if(iter->second.io_conn.connected() )
			iter->second.io_conn.disconnect();

		if( (cond & IO_FLAGS) != net6::IO_NONE)
		{
			iter->second.io_conn = Glib::signal_io().connect(
				sigc::bind(
					sigc::mem_fun(*this, &GSelector::on_io),
					iter->first
				),
				iter->second.io_chan,
				gcond(cond)
			);
		}
	}

	// IO_TIMEOUT changed
	if( (iter->second.cond & net6::IO_TIMEOUT) != (cond & net6::IO_TIMEOUT))
	{
		if(iter->second.time_conn.connected() )
			iter->second.time_conn.disconnect();

		// Timeout is set in set_timeout
	}

	iter->second.cond = cond;
}

void Gobby::GSelector::delete_socket(map_type::iterator iter)
{
	if(iter->second.io_conn.connected() )
		iter->second.io_conn.disconnect();
	if(iter->second.time_conn.connected() )
		iter->second.time_conn.disconnect();

	m_map.erase(iter);
}

net6::io_condition Gobby::GSelector::get(const net6::socket& sock) const
{
	Glib::RecMutex::Lock lock(*m_mutex);
	map_type::const_iterator iter = m_map.find(&sock);

	if(iter == m_map.end() )
		return net6::IO_NONE;
	else
		return iter->second.cond;
}

void Gobby::GSelector::set(const net6::socket& sock, net6::io_condition cond)
{
	// Lock mutex - required for connection establishment which happens
	// in a different thread for the GUI to remain responsive.

	// After the connection to Glib::signal_io() the main thread may be
	// woken up immediately by incoming data and call GSelector::set to
	// send out some data even before the assignment to the
	// sigc::connection in the connecting thread has been finished!
	Glib::RecMutex::Lock lock(*m_mutex);

	map_type::iterator iter = m_map.find(&sock);

	if(cond != net6::IO_NONE)
	{
		if(iter == m_map.end() )
			add_socket(sock, cond);
		else
			modify_socket(iter, cond);
	}
	else if(iter != m_map.end() )
	{
		delete_socket(iter);
	}
}

unsigned long Gobby::GSelector::get_timeout(const net6::socket& sock) const
{
	Glib::RecMutex::Lock lock(*m_mutex);
	map_type::const_iterator iter = m_map.find(&sock);

	// No timeout set for this socket
	if(iter == m_map.end() ) return 0;
	if(!iter->second.time_conn.connected() ) return 0;

	// Returns the remaining time for the timeout to be elapsed
	Glib::TimeVal val;
	val.assign_current_time();
	val -= iter->second.timeout_begin;

	unsigned long elapsed = (val.tv_sec * 1000 + val.tv_usec / 1000);
	if(elapsed >= iter->second.timeout) return 1;

	return iter->second.timeout - elapsed;
}

void Gobby::GSelector::set_timeout(const net6::socket& sock,
                                   unsigned long timeout)
{
	Glib::RecMutex::Lock lock(*m_mutex);

	SelectedSocket* sel_sock = NULL;
	map_type::iterator iter = m_map.find(&sock);

	if(iter != m_map.end() )
	{
		if( (iter->second.cond & net6::IO_TIMEOUT) == net6::IO_TIMEOUT)
			sel_sock = &iter->second;
	}

	if(sel_sock == NULL)
	{
		throw std::logic_error(
			"Gobby::GSelector::set_timeout:\n"
			"Socket is not selected of IO_TIMEOUT"
		);
	}

	if(sel_sock->time_conn.connected() )
		sel_sock->time_conn.disconnect();

	sel_sock->timeout_begin.assign_current_time();
	sel_sock->timeout = timeout;
	sel_sock->time_conn = Glib::signal_timeout().connect(
		sigc::bind(
			sigc::mem_fun(*this, &GSelector::on_timeout),
			sel_sock->sock
		),
		timeout
	);
}

bool Gobby::GSelector::on_io(Glib::IOCondition cond,
                             const net6::socket* sock)
{
	{
		Glib::RecMutex::Lock lock(*m_mutex);
		map_type::const_iterator iter = m_map.find(sock);

		// Has been removed by previous handler
		if(iter == m_map.end() ) return false;

		// Occured condition has been removed by previous handler
		if( (gcond(iter->second.cond) & cond) == gcond(net6::IO_NONE))
			return true;
	}

	// Event handler may destroy the selector, so do not reference
	// m_mutex anymore.
	sock->io_event().emit(ncond(cond) );
	return true;
}

bool Gobby::GSelector::on_timeout(const net6::socket* sock)
{
	{
		Glib::RecMutex::Lock lock(*m_mutex);
		map_type::const_iterator iter = m_map.find(sock);

		// Quite impossible... TODO: throw logic error?
		if(iter == m_map.end() ) return false;
		if( (iter->second.cond & net6::IO_TIMEOUT) == net6::IO_NONE)
			return false;
	}

	// Event handler may destroy the selector, so do not reference
	// m_mutex anymore.
	sock->io_event().emit(net6::IO_TIMEOUT);

	// Timeout is removed after execution
	return false;
}
<commit_msg>[project @ src/gselector.cpp: Added idle call in timout handler.] This is a workaround for a possible bug in glib: A connection to Glib::signal_io is not triggered without waking up the main loop once more.<commit_after>/* gobby - A GTKmm driven libobby client
 * Copyright (C) 2005, 2006 0x539 dev group
 *
 * 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 2 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, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "gselector.hpp"

namespace
{
	inline Glib::IOCondition gcond(net6::io_condition cond)
	{
		Glib::IOCondition g_cond = Glib::IOCondition(0);
		if(cond & net6::IO_INCOMING)
			g_cond |= Glib::IO_IN;
		if(cond & net6::IO_OUTGOING)
			g_cond |= Glib::IO_OUT;
		if(cond & net6::IO_ERROR)
			g_cond |= (Glib::IO_HUP | Glib::IO_NVAL | Glib::IO_ERR);
		return g_cond;
	}

	inline net6::io_condition ncond(Glib::IOCondition cond)
	{
		net6::io_condition n_cond = net6::IO_NONE;
		if(cond & Glib::IO_IN)
			n_cond |= net6::IO_INCOMING;
		if(cond & Glib::IO_OUT)
			n_cond |= net6::IO_OUTGOING;
		if(cond & (Glib::IO_HUP | Glib::IO_NVAL | Glib::IO_ERR) )
			n_cond |= net6::IO_ERROR;
		return n_cond;
	}

	net6::io_condition IO_FLAGS =
		net6::IO_INCOMING | net6::IO_OUTGOING | net6::IO_ERROR;

#ifdef _WIN32
	bool win32_idle_func() { return false; }
#endif
}

Gobby::GSelector::GSelector():
	m_mutex(new Glib::RecMutex)
{
}

Gobby::GSelector::~GSelector()
{
	// Should already be performed by sigc::trackable...
	for(map_type::iterator it = m_map.begin(); it != m_map.end(); ++ it)
		it->second.io_conn.disconnect();
}

void Gobby::GSelector::add_socket(const net6::socket& sock,
                                  net6::io_condition cond)
{
	SelectedSocket& sel = m_map[&sock];

	sel.sock = &sock;
	sel.cond = cond;

	// Timeout is set in set_timeout
	if( (cond & IO_FLAGS) != net6::IO_NONE)
	{
		net6::socket::socket_type fd = sock.cobj();

		sel.io_chan =
#ifdef _WIN32
			Glib::IOChannel::create_from_win32_socket(fd);
#else
			Glib::IOChannel::create_from_fd(fd);
#endif

		sel.io_conn = Glib::signal_io().connect(
			sigc::bind(
				sigc::mem_fun(*this, &GSelector::on_io),
				&sock
			),
			sel.io_chan,
			gcond(cond)
		);
	}
}

void Gobby::GSelector::modify_socket(map_type::iterator iter,
                                     net6::io_condition cond)
{
	// IO_FLAGS did change
	if( (iter->second.cond & IO_FLAGS) != (cond & IO_FLAGS) )
	{
		if(iter->second.io_conn.connected() )
			iter->second.io_conn.disconnect();

		if( (cond & IO_FLAGS) != net6::IO_NONE)
		{
			iter->second.io_conn = Glib::signal_io().connect(
				sigc::bind(
					sigc::mem_fun(*this, &GSelector::on_io),
					iter->first
				),
				iter->second.io_chan,
				gcond(cond)
			);
		}
	}

	// IO_TIMEOUT changed
	if( (iter->second.cond & net6::IO_TIMEOUT) != (cond & net6::IO_TIMEOUT))
	{
		if(iter->second.time_conn.connected() )
			iter->second.time_conn.disconnect();

		// Timeout is set in set_timeout
	}

	iter->second.cond = cond;
}

void Gobby::GSelector::delete_socket(map_type::iterator iter)
{
	if(iter->second.io_conn.connected() )
		iter->second.io_conn.disconnect();
	if(iter->second.time_conn.connected() )
		iter->second.time_conn.disconnect();

	m_map.erase(iter);
}

net6::io_condition Gobby::GSelector::get(const net6::socket& sock) const
{
	Glib::RecMutex::Lock lock(*m_mutex);
	map_type::const_iterator iter = m_map.find(&sock);

	if(iter == m_map.end() )
		return net6::IO_NONE;
	else
		return iter->second.cond;
}

void Gobby::GSelector::set(const net6::socket& sock, net6::io_condition cond)
{
	// Lock mutex - required for connection establishment which happens
	// in a different thread for the GUI to remain responsive.

	// After the connection to Glib::signal_io() the main thread may be
	// woken up immediately by incoming data and call GSelector::set to
	// send out some data even before the assignment to the
	// sigc::connection in the connecting thread has been finished!
	Glib::RecMutex::Lock lock(*m_mutex);

	map_type::iterator iter = m_map.find(&sock);

	if(cond != net6::IO_NONE)
	{
		if(iter == m_map.end() )
			add_socket(sock, cond);
		else
			modify_socket(iter, cond);
	}
	else if(iter != m_map.end() )
	{
		delete_socket(iter);
	}
}

unsigned long Gobby::GSelector::get_timeout(const net6::socket& sock) const
{
	Glib::RecMutex::Lock lock(*m_mutex);
	map_type::const_iterator iter = m_map.find(&sock);

	// No timeout set for this socket
	if(iter == m_map.end() ) return 0;
	if(!iter->second.time_conn.connected() ) return 0;

	// Returns the remaining time for the timeout to be elapsed
	Glib::TimeVal val;
	val.assign_current_time();
	val -= iter->second.timeout_begin;

	unsigned long elapsed = (val.tv_sec * 1000 + val.tv_usec / 1000);
	if(elapsed >= iter->second.timeout) return 1;

	return iter->second.timeout - elapsed;
}

void Gobby::GSelector::set_timeout(const net6::socket& sock,
                                   unsigned long timeout)
{
	Glib::RecMutex::Lock lock(*m_mutex);

	SelectedSocket* sel_sock = NULL;
	map_type::iterator iter = m_map.find(&sock);

	if(iter != m_map.end() )
	{
		if( (iter->second.cond & net6::IO_TIMEOUT) == net6::IO_TIMEOUT)
			sel_sock = &iter->second;
	}

	if(sel_sock == NULL)
	{
		throw std::logic_error(
			"Gobby::GSelector::set_timeout:\n"
			"Socket is not selected of IO_TIMEOUT"
		);
	}

	if(sel_sock->time_conn.connected() )
		sel_sock->time_conn.disconnect();

	sel_sock->timeout_begin.assign_current_time();
	sel_sock->timeout = timeout;
	sel_sock->time_conn = Glib::signal_timeout().connect(
		sigc::bind(
			sigc::mem_fun(*this, &GSelector::on_timeout),
			sel_sock->sock
		),
		timeout
	);
}

bool Gobby::GSelector::on_io(Glib::IOCondition cond,
                             const net6::socket* sock)
{
	{
		Glib::RecMutex::Lock lock(*m_mutex);
		map_type::const_iterator iter = m_map.find(sock);

		// Has been removed by previous handler
		if(iter == m_map.end() ) return false;

		// Occured condition has been removed by previous handler
		if( (gcond(iter->second.cond) & cond) == gcond(net6::IO_NONE))
			return true;
	}

	// Event handler may destroy the selector, so do not reference
	// m_mutex anymore.
	sock->io_event().emit(ncond(cond) );
	return true;
}

bool Gobby::GSelector::on_timeout(const net6::socket* sock)
{
	{
		Glib::RecMutex::Lock lock(*m_mutex);
		map_type::const_iterator iter = m_map.find(sock);

		// Quite impossible... TODO: throw logic error?
		if(iter == m_map.end() ) return false;
		if( (iter->second.cond & net6::IO_TIMEOUT) == net6::IO_NONE)
			return false;
	}

#ifdef _WIN32
	// When the timeout event handler sends data (like net6_ping), glib
	// does not emit a signal_io (with Glib::IO_OUT) until another event
	// occured that wakes up the main loop. This idle event is this other
	// event. Seems to be a bug in Glib/Win32 however.
	Glib::signal_idle().connect(sigc::ptr_fun(win32_idle_func) );
#endif

	// Event handler may destroy the selector, so do not reference
	// m_mutex anymore.
	sock->io_event().emit(net6::IO_TIMEOUT);

	// Timeout is removed after execution
	return false;
}
<|endoftext|>